یک اسمبلی (به انگلیسی: assembly) که در حالت زیرساخت زبان مشترک (CLI) قرار دارد، یک کتابخانه کد کامپایل شدهاست، که از آن در استقرار، نسخهدهی، و امنسازی استفاده میشود. این کتابخانه توسط مایکروسافت برای استفاده در نسخههای جدید ویندوز تعریف شدهاست. دو نوع اسمبلی وجود دارد: اسمبلیهای فرایند (EXE) و اسمبلیهای کتابخانه (DLL). یک اسمبلی فرایند نمایشدهنده یک فرایند است که از کلاسهای تعریفشده در اسمبلی کتابخانه استفاده میکند. اسمبلی CLI شامل کدهایی به زبان CIL هستند، که این کد معمولاً توسط زبان CLI ایجاد شدهاند، و سپس در زمان اجرا، توسط کامپایل درجا، به زبان ماشین کامپایل میگردند. در پیادهسازی چارچوب داتنت، این کامپایلر بخشی از زمان اجرای زبان مشترک (CLR) میباشد.
یک کد اسمبلی، شامل یک یا بیشتر فایل است. به فایلهای کد «پودمان» یا ماژول میگویند. یک اسمبلی شامل بیشتر از یک پودمان کد است. به دلیل آنکه میتوان از زبانهای مختلفی برای ایجاد پودمان کد استفاده کرد، این موضوع از نظر فنی ممکن است تا از چندین زبان مختلف، برای ساخت یک اسمبلی استفادهکرد. با این حال ویژوال استودیو از قابلیت استفاده از زبانهای مختلف در یک اسمبلی، پشتیبانی نمیکند.
نام یک اسمبلی شامل چهار بخش تشکیل است:
از توکن کلید عمومی برای یکتا سازی نام اسمبلی استفاده میشود؛ بنابراین، دو اسمبلی دارای نام نیرومند میتوانند نام فایل PE مشابه داشته باشند، اما هنوز CLI آنها را به عنوان اسمبلیهای متفاوت تشخیص میدهد. سیستم فایلبندی ویندوز (FAT32 و NTFS) تنها نام فایل PE را تشخیص میدهد، بنابراین دو اسمبلی که نام فایل PE مشابه دارند، (اما فرهنگ، نسخه، یا توکن کلید عمومیشان متفاوت است) را نمیتوان در یک فولدر ویندوز قرار داد. برای حل این موضوع، CLI مفهوم GAC را معرفی کردهاست (کوتهنوشت «کاشه اسمبلی جهانی» Global Assembly Cache) که در زمان اجرا به صورت یک فولدر عمل میکند، اما در واقعیت به کمک فولدرهای سیستم فایل تودرتو پیادهسازی شدهاست.
برای جلوگیری از حمله جعل، که در آن قفلشکن[۲] سعی میکند تا یک اسمبلی را به عنوان دیگری جا بزند، باید اسمبلی را با کلید خصوصی امضا کرد. توسعهدهنده اسمبلی مورد نظر، کلید خصوصی را به عنوان یک موضوع سری نگهداری میکند، بنابراین قفلشکن نه به آن دسترسی دارد و نه میتواند آن را به سادگی حدس بزند؛ بنابراین قفلشکن نمیتواند این اسمبلی را به عنوان کد دیگری جابرند، زیرا توانایی امضای درست آن را (بعد از تغییردادن آن) ندارد. امضای اسمبلی شامل درهمسازی بخشهای مهم اسمبلی و سپس رمزگذاری آن درهمشده به کمک کلید خصوصی میباشد. درهمشدهٔ امضا شده همراه با کلید عمومی در اسمبلی قرار میگیرد. از کلید عمومی برای رمزگشایی درهمشده امضاشده استفاده میشود. موقعی که CLR اسمبلی با نام نیرومند را بارگذاری میکند، یک درهمشده از اسمبلی ایجاد میکند، سپس یک عمیات مقایسه با درهمشده رمزگشاییشده انجام میشود. اگر مقایسه موفق باشد، به این معنی است که کلید عمومی موجود در فایل (و از این رو توکن کلید عمومی) با کلید خصوصی که برای امضای اسمبلی استفاده شدهاست، مرتبط میباشد. این موضوع یعنی کلید عمومی موجود در اسمبلی همان کلید عمومی منتشرکننده ی اسمبلی است، ازاینرو از حمله جعل جلوگیری به عمل میآید.
اسمبلیهای CLI میتوانند اطلاعات نسخه داشتهباشند، که به آنها اجازه میدهد تا بیشتر تعارضهایی که بین برنامههای کاربردی، در اثر اسمبلی مشترک به وجود آمده، را از بین ببریم.[۳] اما این موضوع همه تعارضهای نسخهای احتمالی بین اسمبلیها را از بین نمیبرد.[۴]
امنیت دسترسی کد در CLI بر اساس اسمبلیها و شاهدها (به انگلیسی: evidence) هستند. یک شاهد میتواند هر چیزی باشد که از اسمبلی قابل استنتاج است، اما معمولاً از منبع اسمبلی ساخته میشود-- حتی اگر آن اسمبلی از اینترنت، یا اینترانت دانلود گردد، یا روی ماشین محلی نصب شدهباشد (اگر اسمبلی از ماشین دیگری دانلود شود، در محل جعبهشنی در داخل GAC ذخیره خواهدشد، و بنابراین به صورت اسمبلیهای نصب شده محلی با آن عمل نمیشود). مجوزها به کل اسمبلیها اعمال میشوند، و یک اسمبلی از طریق ویژگیهای سفارشیشدهاش میتواند حداقل مجوزهایی را که نیاز دارد را مشخص نماید (فراداده CLI را ببینید). موقعی که اسمبلی بارگذاری شود، CLR از شواهد آن اسمبلی استفاده میکند تا یک «مجموعه مجوز» بسازد که شامل یک یا بیشتر مجوز دسترسی به کد است. سپس CLR بررسی میکند تا مطمئن شود که این مجموعه مجوز شامل مجوزهای لازم تعیین شده توسط اسمبلی میباشد یا نه.
کد CLI میتواند یک درخواست امنیتی دسترسی کد بدهد. این موضوع به این معنی است که کد تنها موقعی یک «عملیات ممتاز» را انجام میدهد که تمام اسمبلیهای تمام شگردهای موجود در پشته تماس، مجوزهای تعین شده را داشته باشند. اگر حتی یکی از اسمبلیها مجوز لازم را نداشته باشد، یک استثنای امنیتی پرتاب خواهد شد.
یک کد CLI میتواند «درخواست پیوندشده» (به انگلیسی: Linked Demand) را برای دستیابی به مجوز از پشته تماس انجام دهد. در این حالت CLR به تنها یک شگرد در محل بالا در پشته تماس، برای مجوز تعیین شده نگاه میکند. در اینجا راهرفتن روی پشته به یک شگرد در پشته تماس محدودسازی شدهاست، که توسط آن شگرد، CRL فرض میکند که بقیه شگردها در «پشته تماس»، مجوز مربوطه را دارند. اسمبلی ترکیبی از فراداده و فایل MSIL است.
به صورت کلی، اسمبلیها باید شامل منابع خنثی از نظر فرهنگ باشند. اگر بخواهید اسمبلیتان را محلیسازی کنید (برای مثال به کمک استفاده از رشتههای مختلف برای محلهای مختلف) باید از اسمبلیهای ماهوارهای استفاده کنید، که نوعی اسمبلی «اختصاصی، و تنها منبع» هستند. همانطور که از نام آن برمیآید، یک ماهواره به یک اسمبلی دیگر که اسمبلی اصلی نامدارد مرتبط است. آن اسمبلی (مثلاً lib.dll) شامل منابع خنثی خواهد بود (که مایکروسافت گفته به زبان انگلیسی بینالمللی است، ولی به معنی ضمنی آن است که انگلیسی آمریکایی است). هر ماهواره دارای نام کتابخانه مرتبط است که به آن یک .resource ملحق شدهاست (مثلاً lib.resouces.dll). به ماهواره یک نام فرهنگ غیرخنثی داده میشود، اما به دلیل آنکه توسط سیستمهای فایل ویندوز موجود (FAT32 و NTFS) نادیده گرفته میشود، این موضوع به این معنی است که میتوان چندین فایل با نام PE یکسان در یک فولدر داشت؛ و به دلیل آنکه این موضوع مقدور نمیباشد، ماهوارهها را باید در زیرفولدرهایی تحت فولدر برنامهکاربردی ذخیرهسازی کرد. برای مثال یک ماهواره با منابع انگلیسی UK، نام CLI ای به صورت "lib.resources Version=0.0.0.0 Culture=en-GB PublicKeyToken=null" خواهد داشت، و نام PE آن lib.resources.dll است، و در یک زیرفولدر که en-GB نام دارد ذخیره میشود.
ماهوارهها توسط یک کلاس CLI که System.Resources.ResourceManager
نام دارد، بارگذاری میشوند. توسعهدهنده باید نام منبع و اطلاعات دربارهٔ اسمبلی اصلی (با منابع خنثی) را تدارک ببیند. کلاس ResourceManager سپس محل ماشین را میخواند، و از این اطلاعات، و نام اسمبلی اصلی، استفاده میکند تا نام ماهواره و نام زیرفولدری که شامل آن است را به دست بیاورد. سپس کلاس ResourceManager
میتواند ماهواره را بارگذاری کند، و به یک منبع محلیسازیشده دست بیابد.
میتوان برای ارجاع به کتابخانه کد اجراپذیر از پرچم /reference از کامپایلر C# استفاده کرد.
اسمبلیهای مشترک نیاز دارند تا به آنها یک «نام نیرومند» داده شود، تا به کمک آن به صورت یکتا، اسمبلی را به نحوی شناسایی کرد که توانایی اشتراک بین برنامههای کاربردی را داشتهباشد. «نام نیرومند» شامل توکن کلید عمومی، فرهنگ، نسخه، و نام فایل PE میباشد. اگر از اسمبلی باید برای اهداف توسعهدادن استفاده شود، که یک اسمبلی مشترک است، فرایند نامگذاری نیرومند تنها شامل «تولید کلید عمومی» است. کلید خصوصی در آن موقع ایجاد نمیشود. کلید خصوصی فقط زمانی ایجاد میشود که اسمبلی استقرار یابد.
یک اسمبلی توسط کد CIL ساخته میشود، که یک زبان میانی است. چارچوب به صورت داخلی، کد CIL (بایتکد) را به کد اسمبلی محلی تبدیل میکند. اگر یک برنامه داشته باشیم که "Hello World" را چاپ میکند، کد CIL معادل برای شگرد به صورت زیر است:
.method private hidebysig static void Main(string[] args) cil managed {
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 )
// Code size 11 (0xb)
.maxstack 1
IL_0000: ldstr "Hello World"
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
IL_000a: ret } // end of method Class1::Main
کد CIL، رشته را به پشته بارگذاری میکند، سپس تابع WriteLine را صدا میزند، و بازمیگردد.