3-Bob: Umumiy va Kuchli Nomlangan Assemblylar

Assemblylarni umumiy foydalanish uchun tayyorlash, kuchli nom berish, GAC bilan ishlash va versiyalarni boshqarish

~55 daqiqa O'qish vaqti
10 ta mavzu Shu bobda
Boshlang'ich Daraja
65-88 bet Asl kitobda

2-bobda biz assemblylarni qurish, modullarni birlashtirish va ilovalarni oddiy deploy qilish haqida gaplashdik. O'sha bobda men faqat shaxsiy deploy qilingan assemblylar (privately deployed assemblies) haqida gapirib o'tdim — ya'ni ilova papkasiga joylashtirilgan, boshqa ilovalar bilan bo'lishilmaydigan assemblylar.

Ushbu bobda biz bir qadam oldinga o'tamiz va umumiy (shared) assemblylar hamda kuchli nomlangan (strongly named) assemblylar haqida batafsil gaplashamiz. Kuchli nomlash mexanizmi assemblylarga yagona identifikatsiya beradi, bu esa bir nechta ilovalar o'rtasida assemblylarni xavfsiz tarzda almashish imkonini yaratadi. Shuningdek, biz Global Assembly Cache (GAC), kechiktirilgan imzolash (delayed signing), runtime turlarni qanday hal qilishi va kengaytirilgan administrativ konfiguratsiya haqida o'rganamiz.

Ikki Xil Assembly, Ikki Xil Deploy

Assembly ikki xil usulda deploy qilinishi mumkin: shaxsiy (privately) va global (globally). Shaxsiy deploy qilingan assembly — bu ilovaning bazaviy papkasida yoki uning quyi papkalaridan birida joylashtirilgan assembly. Zaif nomlangan (weakly named) assembly faqat shaxsiy deploy qilinishi mumkin. Men shaxsiy deploy qilingan assemblylar haqida 2-bobda gapirgan edim.

Global deploy qilingan assembly — bu assemblyga havola aniqlanganda CLR avtomatik ravishda ko'rib chiqadigan ma'lum bir joyga o'rnatilgan assembly. Kuchli nomlangan assembly shaxsiy yoki global tarzda deploy qilinishi mumkin. Men bu bobda kuchli nomlangan assemblylarni qanday yaratish va deploy qilishni tushuntiraman.

3-1 jadval assembly turlarini va ularning deploy qilinish usullarini umumlashtiradi.

Assembly turi Shaxsiy deploy qilinishi mumkinmi? Global deploy qilinishi mumkinmi?
Zaif nomlangan (Weakly named) Ha Yo'q
Kuchli nomlangan (Strongly named) Ha Ha
Eslatma

Zaif nomlangan assemblylar faqat shaxsiy deploy qilinishi mumkin, chunki ularning yagona identifikatsiyasi yo'q. Kuchli nomlangan assemblylar esa ham shaxsiy, ham global tarzda deploy qilinishi mumkin, chunki ular to'rt xil atribut bilan yagona identifikatsiya qilinadi.

Assemblyga Kuchli Nom Berish

Agar bir nechta ilovalar assemblyga kirishi kerak bo'lsa, assembly ma'lum bir papkaga joylashtirilishi kerak va CLR unga havola aniqlanganda avtomatik ravishda bu papkaga qarashi kerak. Biroq, biz muammoga duch kelamiz: ikki (yoki undan ko'p) kompaniya bir xil fayl nomiga ega assemblylarni ishlab chiqarishi mumkin. Keyin, agar bu assemblylarning ikkisi ham bir xil ma'lum papkaga nusxalansa, oxirgi o'rnatilgani g'olib bo'ladi va eski assemblyni ishlatayotgan barcha ilovalar endi to'g'ri ishlamaydi. (Aynan shuning uchun bugungi kunda Windows da DLL hell mavjud — umumiy DLL lar System32 papkasiga nusxalanadi.)

Shubhasiz, assemblylarni faqat fayl nomi bo'yicha farqlash yetarli emas. CLR assemblylarga yagona identifikatsiya beradigan mexanizmni qo'llab-quvvatlashi kerak. Aynan kuchli nomlangan assembly (strongly named assembly) atamasi shu narsani anglatadi. Kuchli nomlangan assembly to'rt xil atributdan iborat bo'lib, ular assemblyni yagona identifikatsiya qiladi: fayl nomi (kengaytmasiz), versiya raqami, madaniyat identifikatsiyasi va ochiq kalit (public key). Ochiq kalitlar juda katta raqamlar bo'lganligi sababli, biz tez-tez ochiq kalitdan olingan kichik xesh qiymatni ishlatamiz. Bu xesh qiymat ochiq kalit tokeni (public key token) deb ataladi.

Quyidagi assembly identifikatsiya qatorlari (ba'zan assembly display name deb ataladi) to'rtta butunlay farqli assembly fayllarini identifikatsiya qiladi:

Assembly identifikatsiya qatorlari
"MyTypes, Version=1.0.8123.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

"MyTypes, Version=1.0.8123.0, Culture="en-US", PublicKeyToken=b77a5c561934e089"

"MyTypes, Version=2.0.1234.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

"MyTypes, Version=1.0.8123.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"

Birinchi qator MyTypes.exe yoki MyTypes.dll nomli assembly faylini identifikatsiya qiladi (fayl kengaytmasini assembly identifikatsiya qatoridan aniqlab bo'lmaydi). Assemblyni ishlab chiqargan kompaniya bu assemblining 1.0.8123.0 versiyasini yaratmoqda va assemblydagi hech narsa biron madaniyatga bog'liq emas, chunki Culture neutral ga o'rnatilgan.

Ikkinchi qator AQSh ingliz tili madaniyatiga xos assemblyni identifikatsiya qiladi. Uchinchi qator assemblyning boshqa versiyasini (2.0.1234.0) identifikatsiya qiladi. To'rtinchi qator esa boshqa ochiq kalit tokeniga ega bo'lgan, ya'ni boshqa kompaniya tomonidan yaratilgan assemblyni identifikatsiya qiladi.

Microsoft boshqa yagona identifikatsiya texnologiyalari (GUID, URL, URN kabilar) o'rniga standart ochiq/maxfiy kalit kriptografik texnologiyalarini tanladi. Kriptografik texnologiyalar mashinaga o'rnatilgan assemblyning bitlarining yaxlitligini tekshirish usulini beradi va ruxsatlarni har bir nashriyotchi asosida berishga imkon beradi. Shunday qilib, assemblylarini yagona belgilashni xohlaydigan kompaniya ochiq/maxfiy kalit juftligini yaratishi kerak. Keyin ochiq kalit assembly bilan bog'lanishi mumkin. Hech qanday ikki kompaniya bir xil ochiq/maxfiy kalit juftligiga ega bo'lmasligi kerak va aynan shu farq ikki kompaniyaga bir xil nom, versiya va madaniyatga ega assemblylar yaratishga hech qanday ziddiyatsiz imkon beradi.

Eslatma

System.Reflection.AssemblyName klassi assembly nomini yaratishni va assemblyning turli qismlarini olishni osonlashtiradigan yordamchi klassdir. Bu klass CultureInfo, FullName, KeyPair, Name va Version kabi bir nechta ochiq xususiyatlarni va GetPublicKey, GetPublicKeyToken, SetPublicKey va SetPublicKeyToken kabi ochiq metodlarni taklif qiladi.

2-bobda men sizga assembly faylini qanday nomlash va assembly versiyasini va madaniyatni qanday qo'llashni ko'rsatdim. Zaif nomlangan assembly manifest metadatasida assembly versiyasi va madaniyat atributlariga ega bo'lishi mumkin; biroq, CLR har doim versiya raqamini e'tiborsiz qoldiradi va satellite assemblyni qidirishda faqat madaniyat ma'lumotlaridan foydalanadi. Zaif nomlangan assemblylar har doim shaxsiy deploy qilinganligi sababli, CLR shunchaki assembly nomini (assembly fayliga .dll yoki .exe kengaytmasini qo'shib) ilovaning bazaviy papkasida yoki XML konfiguratsiya faylining privatePath atributida ko'rsatilgan quyi papkalarida qidiradi.

Kuchli nomlangan assembly fayl nomi, assembly versiyasi va madaniyatga ega. Bundan tashqari, kuchli nomlangan assembly nashriyotchining maxfiy kaliti bilan imzolangan. Assembly maxfiy kaliti bilan imzolanishi uning yaxlitligini ta'minlaydi.

SN.exe — Kuchli Nom Yordamchisi

Kuchli nomlangan assembly yaratishning birinchi bosqichi — .NET Framework SDK va Microsoft Visual Studio bilan birga keladigan Strong Name yordamchisi — SN.exe dan foydalanib kalit olishdir. Bu yordamchi buyruq qatori kalitlariga qarab bir qancha imkoniyatlarni taklif qiladi. E'tibor bering, SN.exe ning barcha buyruq qatori kalitlari katta-kichik harfga sezgir.

Ochiq/maxfiy kalit juftligini yaratish uchun SN.exe ni quyidagicha ishga tushirasiz:

Buyruq qatori
SN -k MyCompany.snk

Bu qator SN.exe ga MyCompany.snk nomli fayl yaratishni aytadi. Bu fayl ochiq va maxfiy kalit raqamlarini ikkilik formatda saqlaydi.

Ochiq kalit raqamlari juda katta. Agar siz ochiq va maxfiy kalitlarni o'z ichiga olgan fayl yaratganingizdan so'ng haqiqiy ochiq kalitni ko'rishni xohlasangiz, SN.exe yordamchisini ikki marta bajarishingiz kerak. Avval SN.exe ni -p kaliti bilan chaqirib, faqat ochiq kalitni o'z ichiga olgan fayl yaratasiz:

Buyruq qatori
SN -p MyCompany.snk MyCompany.PublicKey sha256

Keyin SN.exe ni -tp kaliti bilan chaqirib, faqat ochiq kalitni o'z ichiga olgan faylni berasiz:

Buyruq qatori
SN -tp MyCompany.PublicKey

Men bu qatorni bajarganimda, quyidagi chiqishni oldim:

Chiqish
Microsoft (R) .NET Framework Strong Name Utility  Version 4.0.30319.17929
Copyright (c) Microsoft Corporation. All rights reserved.

Public key (hash algorithm: sha256):
00240000048000009400000006020000002400005253413100040000010001003f9d621b702111
850be453b92bd6a58c020eb7b804f75d67ab302047fc786ffa3797b669215afb4d814a6f294010
b233bac0b8c8098ba809855da256d964c0d07f16463d918d651a4846a62317328cac893626a550
69f21a125bc03193261176dd629eaceb6c90d36858de3fcb781bfcb8b817936a567cad608ae672b6
1fb80eb0

Public key token is 3db32f38c8b42c9a

SN.exe yordamchisi maxfiy kalitni ko'rish uchun hech qanday usul taklif qilmaydi.

Ochiq kalitlarning hajmi ular bilan ishlashni qiyinlashtiradi. Ishni osonlashtirish (va oxirgi foydalanuvchilar uchun ham), ochiq kalit tokenlari (public key tokens) yaratilgan. Ochiq kalit tokeni ochiq kalitning 64-bitli xeshidir. SN.exe ning -tp kaliti chiqishning oxirida to'liq ochiq kalitga mos keladigan ochiq kalit tokenini ko'rsatadi.

Assemblyni Imzolash

Endi siz ochiq/maxfiy kalit juftligini qanday yaratishni bilganingizdan so'ng, kuchli nomlangan assembly yaratish oddiy. Assemblyni kompilyatsiya qilayotganingizda, /keyfile:<fayl> kompilyator kalitini ishlatasiz:

Buyruq qatori
csc /keyfile:MyCompany.snk Program.cs

C# kompilyator bu kalitni ko'rganda, ko'rsatilgan faylni (MyCompany.snk) ochadi, assembly maxfiy kalit bilan imzolaydi va ochiq kalitni manifestga joylshtiradi. E'tibor bering, siz faqat manifest o'z ichiga olgan faylni imzolaysiz; assemblyning boshqa fayllarini aniq imzolab bo'lmaydi.

Agar siz Visual Studio dan foydalanayotgan bo'lsangiz, loyihangiz xususiyatlarini ko'rsatib, Signing tabni bosib, Sign The Assembly katakchasini belgilab va keyin Choose A Strong Name Key File kombo qutisidan <New...> opsiyasini tanlab yangi ochiq/maxfiy kalit faylini yaratishingiz mumkin.

Assemblyni imzolash deganda nima tushunilishini ko'rib chiqaylik. Kuchli nomlangan assembly qurganingizda, assemblyning FileDef manifest metadata jadvali assemblyni tashkil etuvchi barcha fayllar ro'yxatini o'z ichiga oladi. Har bir faylning nomi manifestga qo'shilganda, faylning tarkibi xeshlanadi va bu xesh qiymat FileDef jadvalida fayl nomi bilan birga saqlanadi. Siz standart xesh algoritmini AL.exe ning /algid kaliti bilan yoki assembly darajasidagi System.Reflection.AssemblyAlgorithmIdAttribute maxsus atributi bilan bekor qilishingiz mumkin. Standart holda SHA-1 algoritmi ishlatiladi.

Manifest o'z ichiga olgan PE fayli qurilganidan so'ng, PE faylining butun tarkibi (Authenticode imzosi, assemblyning kuchli nom ma'lumotlari va PE sarlavha nazorat summasi bundan mustasno) xeshlanadi. Bu xesh qiymat nashriyotchining maxfiy kaliti bilan imzolanadi va natijadagi RSA raqamli imzosi PE fayl ichidagi ajratilgan bo'limda saqlanadi (xeshga kiritilmagan). PE faylining CLR sarlavhasi raqamli imzo fayldagi qayerda joylashganligini aks ettirish uchun yangilanadi.

Nashriyotchining ochiq kaliti shuningdek ushbu PE fayl ichidagi AssemblyDef manifest metadata jadvaliga joylashtiriladi. Fayl nomi, assembly versiyasi, madaniyat va ochiq kalitning kombinatsiyasi bu assemblyga yagona bo'lishiga kafolatlangan kuchli nomni beradi. Ikki kompaniya bir xil ochiq/maxfiy kalit juftligini bo'lishmagan bo'lsa, ikki kompaniya ham OurLibrary nomli assembly ishlab chiqarishi mumkin emas.

Assembly Identifikatsiyasi va Havola Qilish

Shu nuqtada assembly va uning barcha fayllari paketlanishga va tarqatilishga tayyor.

2-bobda tasvirlanganidek, manba kodingizni kompilyatsiya qilganingizda, kompilyator kodingiz havola qilayotgan turlar va a'zolarni aniqlaydi. Siz havolalangan assemblylarni kompilyatorga ko'rsatishingiz kerak. C# kompilyatorida /reference kompilyator kalitidan foydalanasiz. Kompilyatorning vazifasining bir qismi natija boshqariladigan modul ichida AssemblyRef metadata jadvalini yaratishdir. AssemblyRef metadata jadvalidagi har bir yozuv havolalangan assemblyning nomini (yo'l va kengaytmasiz), versiya raqami, madaniyat va ochiq kalit ma'lumotlarini ko'rsatadi.

Muhim

Ochiq kalitlar juda katta raqamlar bo'lganligi va bitta assembly ko'p assemblylarga havola qilishi mumkinligi sababli, natija faylining umumiy hajmining katta foizi ochiq kalit ma'lumotlari bilan band bo'ladi. Saqlash joyini tejash uchun, Microsoft ochiq kalitni xeshlaydi va xeshlangan qiymatning oxirgi 8 baytini oladi. Bu qisqartirilgan ochiq kalit qiymatlari — ochiq kalit tokenlari deb nomlanadi — aslida AssemblyRef jadvalida saqlanadi. Umuman olganda, dasturchilar va oxirgi foydalanuvchilar to'liq ochiq kalit qiymatlaridan ko'ra ochiq kalit token qiymatlarini ko'proq ko'rishadi.

E'tibor bering, CLR hech qachon xavfsizlik yoki ishonch qarorlarini qabul qilishda ochiq kalit tokenlarini ishlatmaydi, chunki bir nechta ochiq kalit bitta ochiq kalit tokeniga xeshlanishi mumkin.

Oddiy klass kutubxonasi DLL fayli uchun AssemblyRef metadata ma'lumotlari (ILDasm.exe yordamida olingan) quyida ko'rsatilgan:

AssemblyRef metadata (ILDasm chiqishi)
AssemblyRef #1 (23000001)
-------------------------------------------------------
Token: 0x23000001
Public Key or Token: b7 7a 5c 56 19 34 e0 89
Name: mscorlib
Version: 4.0.0.0
Major Version: 0x00000004
Minor Version: 0x00000000
Build Number: 0x00000000
Revision Number: 0x00000000
Locale: <null>
HashValue Blob:
Flags: [none] (00000000)

Bundan ko'rinib turibdiki, DLL assembly quyidagi atributlarga mos keladigan assemblydagi turga havola qiladi:

Assembly havola qatori
"MSCorLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

Agar siz DLL assemblining AssemblyDef metadata jadvaliga qarasangiz, quyidagini ko'rasiz:

AssemblyDef metadata (ILDasm chiqishi)
Assembly
-------------------------------------------------------
Token: 0x20000001
Name : SomeClassLibrary
Public Key    :
Hash Algorithm : 0x00008004
Version: 3.0.0.0
Major Version: 0x00000003
Minor Version: 0x00000000
Build Number: 0x00000000
Revision Number: 0x00000000
Locale: <null>
Flags : [none] (00000000)

Bu ekvivalent:

Assembly identifikatsiya qatori
"SomeClassLibrary, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null"

Bu qatorda ochiq kalit tokeni ko'rsatilmagan, chunki DLL assembly ochiq/maxfiy kalit juftligi bilan imzolanmagan, bu esa uni zaif nomlangan assembly qiladi. Agar men SN.exe dan foydalanib kalit fayli yaratganimda va /keyfile kompilyator kaliti bilan kompilyatsiya qilganimda, natija assembly imzolangan bo'lar edi. ILDasm.exe bilan yangi assemblyning metadatasini ko'rsam, AssemblyDef yozuvidagi Public Key maydonidan keyin baytlar ko'rinadi va assembly kuchli nomlangan bo'lar edi. Aytgancha, AssemblyDef yozuvi har doim to'liq ochiq kalitni saqlaydi, ochiq kalit tokenini emas. To'liq ochiq kalit faylning buzilmaganligini ta'minlash uchun zarur. Men kuchli nomlangan assemblylarning buzilishga chidamliligini ushbu bobda keyinroq tushuntiraman.

Global Assembly Cache (GAC)

Endi siz kuchli nomlangan assemblyni qanday yaratishni bilganingizdan so'ng, bu assemblyni qanday deploy qilish va CLR assemblyni topish va yuklash uchun qanday ma'lumotdan foydalanishini o'rganish vaqti keldi.

Agar assemblyga bir nechta ilovalar kirishi kerak bo'lsa, assembly ma'lum bir papkaga joylashtirilishi va assemblyga havola aniqlanganda CLR avtomatik ravishda bu papkaga qarashi kerak. Bu ma'lum joy global assembly cache (GAC) deb ataladi. GAC ning aniq joylashuvi .NET Framework ning turli versiyalari bilan o'zgarishi mumkin bo'lgan amalga oshirish tafsilotidir. Biroq, siz uni odatda quyidagi papkada topishingiz mumkin:

GAC joylashuvi
%SystemRoot%\Microsoft.NET\Assembly

GAC papkasi tuzilishga ega. U ko'p quyi papkalarni o'z ichiga oladi va quyi papkalar nomlarini yaratish uchun algoritm ishlatiladi. Siz hech qachon assembly fayllarini GAC ga qo'lda nusxalamasligingiz kerak; buning o'rniga, bu vazifani bajarish uchun vositalardan foydalanishingiz kerak. Bu vositalar GAC ning ichki tuzilishini va to'g'ri quyi papka nomlarini qanday yaratishni biladi.

GACUtil.exe Vositasi

Ishlab chiqish va sinovdan o'tkazish jarayonida kuchli nomlangan assemblyni GAC ga o'rnatish uchun eng keng tarqalgan vosita — GACUtil.exe. Bu vositani hech qanday buyruq qatori argumentlarisiz ishga tushirsangiz, quyidagi foydalanishni ko'rsatadi:

GACUtil.exe buyruqlari
Foydalanish: Gacutil <buyruq> [ <opsiyalar> ]
Buyruqlar:
  /i <assembly_yo'li> [ /r <...> ] [ /f ]
    Assemblyni global assembly cache ga o'rnatadi.

  /il <assembly_ro'yxat_fayli> [ /r <...> ] [ /f ]
    Bir yoki bir nechta assemblylarni global assembly cache ga o'rnatadi.

  /u <assembly_nomi> [ /r <...> ]
    Assemblyni global assembly cache dan o'chiradi.

  /ul <assembly_ro'yxat_fayli> [ /r <...> ]
    Bir yoki bir nechta assemblylarni global assembly cache dan o'chiradi.

  /l [ <assembly_nomi> ]
    Global assembly cache ni <assembly_nomi> bo'yicha filtrlangan holda ro'yxatlaydi.

  /lr [ <assembly_nomi> ]
    Global assembly cache ni barcha kuzatilgan havolalar bilan ro'yxatlaydi.

  /cdl
    Yuklab olish keshining tarkibini o'chiradi.

  /ldl
    Yuklab olish keshining tarkibini ro'yxatlaydi.

  /?
    Batafsil yordam ekranini ko'rsatadi.

Opsiyalar:
  /r <havola_sxemasi> <havola_id> <tavsif>
    O'rnatish (/i, /il) yoki o'chirish (/u, /ul) uchun kuzatilgan havolani belgilaydi.

  /f
    Assemblyni qayta o'rnatishga majburlaydi.

  /nologo
    Logo bannerini ko'rsatmaydi.

  /silent
    Barcha chiqishni yashiradi.

Ko'rib turganingizdek, assemblyni GAC ga o'rnatish uchun GACUtil.exe ni /i kaliti bilan, GAC dan o'chirish uchun esa /u kaliti bilan chaqirishingiz mumkin. E'tibor bering, siz zaif nomlangan assemblyni GAC ga hech qachon joylashtira olmaysiz. Agar siz zaif nomlangan assemblyning fayl nomini GACUtil.exe ga bersangiz, u quyidagi xato xabarini ko'rsatadi: Failure adding assembly to the cache: Attempt to install an assembly without a strong name.

Eslatma

Standart holda, GAC faqat Windows Administrators guruhiga a'zo bo'lgan foydalanuvchi tomonidan boshqarilishi mumkin. GACUtil.exe yordamchini ishga tushirgan foydalanuvchi bu guruhning a'zosi bo'lmasa, assembly o'rnatish yoki o'chirish muvaffaqiyatsiz bo'ladi.

GACUtil.exe ning /i kalitidan foydalanish dasturchi uchun sinovda juda qulay. Biroq, agar siz assemblni ishlab chiqarish muhitida GAC ga deploy qilish uchun GACUtil.exe dan foydalansangiz, assemblyni o'rnatish yoki o'chirish uchun /i yoki /u ga qo'shimcha ravishda GACUtil.exe ning /r kalitini ham ishlatish tavsiya etiladi. /r kaliti assemblyni Windows o'rnatish va o'chirish tizimi bilan integratsiya qiladi. Bu kalitni ishlatganingizda, u tizimga qaysi ilova assemblyni talab qilishini aytadi va ilovani assembly bilan bog'laydi.

Eslatma

Agar kuchli nomlangan assembly cabinet (.cab) faylida paketlangan yoki biron tarzda siqilgan bo'lsa, GACUtil.exe dan foydalanib assemblyning fayllarini GAC ga o'rnatishdan oldin assemblyning faylini vaqtinchalik fayl(lar)ga ochishingiz kerak. Assemblyning fayllari o'rnatilganidan so'ng, vaqtinchalik fayl(lar)ni o'chirish mumkin.

GACUtil.exe vositasi oxirgi foydalanuvchi .NET Framework qayta tarqatiladigan paketi bilan birga kelmaydi. Agar ilovangiz GAC ga deploy qilmoqchi bo'lgan assemblylarni o'z ichiga olsa, siz Windows Installer (MSI) dan foydalanishingiz kerak, chunki MSI oxirgi foydalanuvchi mashinalarida bo'lishiga kafolatlangan yagona vosita va assemblylarni GAC ga o'rnatish qobiliyatiga ega.

Muhim

Assembly fayllarini GAC ga global deploy qilish — bu assemblyni ro'yxatdan o'tkazishning bir shakli, garchi haqiqiy Windows registri hech qanday tarzda ta'sirlanmasa ham. Assemblylarni GAC ga o'rnatish oddiy ilova o'rnatish, zaxiralash, tiklash, ko'chirish va o'chirish maqsadlarini buzadi. Shuning uchun global deploy qilishdan qochish va iloji boricha shaxsiy deploy qilishdan foydalanish tavsiya etiladi.

GAC da assemblyni "ro'yxatdan o'tkazish" nima uchun kerak? Aytaylik, ikki kompaniya har biri bitta fayldan iborat OurLibrary assemblyni ishlab chiqardi: OurLibrary.dll. Shubhasiz, bu fayllarning ikkalasi ham bir papkaga kirishi mumkin emas, chunki oxirgi o'rnatilgani birinchisini qayta yozadi. Assemblyni GAC ga o'rnatganingizda, maxsus quyi papkalar %SystemRoot%\Microsoft.NET\Assembly papkasi ostida yaratiladi va assembly fayllari ushbu quyi papkalardan biriga nusxalanadi.

Odatda, hech kim GAC quyi papkalarini tekshirmaydi, shuning uchun GAC tuzilishi siz uchun muhim bo'lmasligi kerak. Vositalar va CLR tuzilishni bilsa yetarli.

Kuchli Nomlangan Assemblyga Havola Qilib Assembly Qurish

Assembly qurganingizda, assembly boshqa kuchli nomlangan assemblylarga havola qiladi. Bu System.Object MSCorLib.dll da aniqlanganligi sababli shunday — bu esa kuchli nomlangan assembly. Biroq, assemblyning Microsoft, uchinchi tomon yoki o'z tashkilotingiz tomonidan nashr etilgan boshqa kuchli nomlangan assemblylardagi turlarni ham havolashi ehtimoli bor.

2-bobda men sizga CSC.exe ning /reference kompilyator kalitidan foydalanib havola qilmoqchi bo'lgan assembly fayl nomlarini ko'rsatish usulini ko'rsatgan edim. Agar fayl nomi to'liq yo'l bo'lsa, CSC.exe ko'rsatilgan faylni yuklaydi va assemblyni qurish uchun uning metadata ma'lumotlaridan foydalanadi. 2-bobda aytib o'tganidek, yo'lsiz fayl nomini ko'rsatsangiz, CSC.exe assemblyni quyidagi papkalarda (taqdimot tartibi bo'yicha) qidirishga harakat qiladi:

  1. Ishchi papka (Working directory).
  2. CSC.exe faylini o'z ichiga olgan papka. Bu papka CLR DLL larini ham o'z ichiga oladi.
  3. /lib kompilyator kaliti yordamida ko'rsatilgan papkalar.
  4. LIB muhit o'zgaruvchisi yordamida ko'rsatilgan papkalar.

Demak, agar siz Microsoft ning System.Drawing.dll assemblyga havola qiluvchi assembly qurayotgan bo'lsangiz, CSC.exe ni chaqirganingizda /reference:System.Drawing.dll kalitini ko'rsatishingiz mumkin. Kompilyator oldingi papkalarni tekshiradi va System.Drawing.dll faylini CSC.exe faylini o'z ichiga olgan papkada topadi — bu CLR ning DLL larini o'z ichiga olgan papka bilan bir xil.

.NET Framework ni o'rnatganingizda, Microsoft ning assembly fayllari aslida ikki marta o'rnatiladi. Bir to'plam kompilyator/CLR papkasiga, ikkinchi to'plam GAC quyi papkasiga o'rnatiladi. Kompilyator/CLR papkasidagi fayllar assemblyni osongina qurishingiz uchun, GAC dagi nusxalar esa ish vaqtida yuklanishi uchun mavjud.

CSC.exe havolalangan assemblylar uchun GAC ga qaramasligining sababi shunki, siz assembly fayliga yo'lni yoki GAC tuzilishini bilishingiz kerak bo'lar edi — bu esa hujjatlashtirilmagan. Muqobil ravishda, CSC.exe sizga uzoq, lekin biroz yoqimliroq ko'rinadigan qatorni ko'rsatishga ruxsat berishi mumkin edi, masalan "System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a." Bu echimlarning ikkisi ham assembly fayllarini foydalanuvchining qattiq diskida ikki marta o'rnatilganidan yomonroq deb topildi.

Bundan tashqari, kompilyator/CLR papkasidagi assemblylar faqat metadata o'z ichiga oladi — ya'ni ular mashina-agnostik. Ularda IL kodi qurilish vaqtida kerak emasligi sababli, bu papkada assemblyning x86, x64 va ARM versiyalari bo'lishi shart emas. GAC dagi assemblylar esa metadata va IL kodini o'z ichiga oladi. Kodni ma'lum bir CPU arxitekturasi uchun nozik sozlash mumkin bo'lganligi sababli, GAC assemblyning bir nechta nusxasini o'z ichiga olishga imkon beradi; har bir nusxa har bir CPU arxitekturasi uchun alohida quyi papkada joylashgan.

Kuchli Nomlangan Assemblylar Buzilishga Chidamli

Assemblyni maxfiy kalit bilan imzolash va ochiq kalitni PE fayl ichiga joylshtirish CLR ga assemblyning o'zgartirilmagan yoki buzilmaganligini tekshirish imkonini beradi. Assembly GAC ga o'rnatilganda, tizim manifest o'z ichiga olgan faylning tarkibini xeshlaydi va xesh qiymatini PE fayl ichiga joylashtirilgan RSA raqamli imzo qiymati bilan solishtiradi (ochiq kalit bilan imzoni ochganidan keyin). Agar qiymatlar bir xil bo'lsa, faylning tarkibi buzilmagan. Bundan tashqari, tizim assemblyning boshqa fayllarining tarkibini xeshlaydi va xesh qiymatlarini manifest faylining FileDef jadvalida saqlangan xesh qiymatlari bilan solishtiradi. Agar biron xesh qiymatlari mos kelmasa, assemblyning fayllaridan kamida bittasi buzilgan va assemblyni GAC ga o'rnatish muvaffaqiyatsiz bo'ladi.

Ilova assemblyga bog'lanishi kerak bo'lganda, CLR havolalangan assemblyning xususiyatlarini (nom, versiya, madaniyat va ochiq kalit) ishlatib assemblyni GAC da topadi. Agar havolalangan assembly topilsa, uning quyi papkasi qaytariladi va manifest o'z ichiga olgan fayl yuklanadi. Assemblyni shu tarzda topish chaqiruvchiga ish vaqtida yuklangan assembly kompilyatsiya vaqtida kompilyatsiya qilingan kodi bilan bir xil nashriyotchi tomonidan yaratilganligiga kafolat beradi. Bu kafolat mumkin, chunki havolaychi assemblyning AssemblyRef jadvalidagi ochiq kalit tokeni havolalangan assemblyning AssemblyDef jadvalidagi ochiq kalitga mos keladi.

Agar havolalangan assembly GAC da bo'lmasa, CLR ilovaning bazaviy papkasida va keyin ilovaning konfiguratsiya faylida aniqlangan har qanday shaxsiy yo'llarda qidiradi; keyin, agar ilova MSI yordamida o'rnatilgan bo'lsa, CLR MSI dan assemblyni topishni so'raydi. Agar assembly bu joylarning hech birida topilmasa, bog'lanish muvaffaqiyatsiz bo'ladi va System.IO.FileNotFoundException xatosi yuzaga keladi.

Kuchli nomlangan assembly fayllari GAC dan boshqa joydan yuklanganda (ilovaning bazaviy papkasi yoki konfiguratsiya faylidagi codeBase elementi orqali), CLR xesh qiymatlarini solishtiradi. Boshqacha aytganda, fayl har safar ilova ishga tushirilganda xeshlanadi. Bu unumdorlik zarari, lekin assemblyning tarkibining buzilmaganligiga ishonch uchun to'lov. CLR ish vaqtida mos kelmaydigan xesh qiymatlarini aniqlaganda, System.IO.FileLoadException xatosini tashlaydi.

Eslatma

Kuchli nomlangan assembly GAC ga o'rnatilganda, tizim manifest o'z ichiga olgan fayl buzilmaganligiga ishonch hosil qiladi. Bu tekshirish faqat bir marta, o'rnatish vaqtida sodir bo'ladi. Bundan tashqari, unumdorlikni yaxshilash uchun, CLR kuchli nomlangan assemblyning buzilmaganligini tekshirmaydi, agar assembly to'liq ishonchli bo'lsa va to'liq ishonchli AppDomain ga yuklanayotgan bo'lsa. Boshqa tomondan, kuchli nomlangan assembly GAC dan boshqa papkadan yuklanganda, CLR assemblyning manifest faylini tekshirib, fayl tarkibi buzilmaganligiga ishonch hosil qiladi — bu har safar fayl yuklanganda qo'shimcha unumdorlik zarari keltirib chiqaradi.

Kechiktirilgan Imzolash (Delayed Signing)

Ushbu bobda avvalroq men SN.exe vositasi ochiq/maxfiy kalit juftliklarini qanday ishlab chiqarish mumkinligini muhokama qildim. Bu vosita Windows tomonidan taqdim etilgan Crypto API ga chaqiruvlar qilish orqali kalitlarni yaratadi. Bu kalitlar fayllarda yoki boshqa saqlash qurilmalarida saqlanishi mumkin. Masalan, yirik tashkilotlar (Microsoft kabi) qaytarilgan maxfiy kalitni seyfda qulflangan apparat qurilmasida saqlaydi; kompaniyada faqat bir nechta odam maxfiy kalitga kirish huquqiga ega. Bu ehtiyot chorasi maxfiy kalitning buzilishini oldini oladi va kalit yaxlitligini ta'minlaydi. Ochiq kalit esa, nomi aytib turibdi, ommaviy va erkin tarqatiladi.

Kuchli nomlangan assemblyni paketlashga tayyor bo'lganingizda, uni imzolash uchun xavfsiz maxfiy kalitdan foydalanishingiz kerak bo'ladi. Biroq, assemblyni ishlab chiqish va sinovdan o'tkazish jarayonida xavfsiz maxfiy kalitga kirish noqulay bo'lishi mumkin. Shuning uchun .NET Framework kechiktirilgan imzolash (delayed signing), ba'zan qisman imzolash (partial signing) deb ataladigan mexanizmni qo'llab-quvvatlaydi.

Kechiktirilgan imzolash sizga faqat kompaniyangizning ochiq kalitidan foydalanib assembly qurishga imkon beradi; maxfiy kalit shart emas. Ochiq kalitdan foydalanish bu assemblyga havola qiluvchi assemblylarning AssemblyRef metadata yozuvlarida to'g'ri ochiq kalitni joylashtirishga imkon beradi. Shuningdek, u assemblyni GAC ga joylashtirishga imkon beradi. Agar siz faylni kompaniyangizning maxfiy kaliti bilan imzolamasangiz, siz assemblyning fayllarini xeshlash va faylga raqamli imzoni joylashtirishning barcha buzilishdan himoya afzalliklarini yo'qotasiz. Lekin bu muammo bo'lmasligi kerak, chunki siz kechiktirilgan imzolashni faqat ishlab chiqish vaqtida ishlatasiz, paketlash va deploy qilishga tayyor bo'lganingizda emas.

Asosan, kompaniyangizning ochiq kalit qiymatini faylga olasiz va fayl nomini assembly qurishda ishlatiladigan har qanday yordamchi dasturga berasiz. (Ushbu bobda avvalroq ko'rsatganidek, ochiq/maxfiy kalit juftligini o'z ichiga olgan fayldan ochiq kalitni ajratish uchun SN.exe ning -p kalitini ishlatishingiz mumkin.) Shuningdek, vositaga assemblyni kechiktirilgan imzolash kerakligini, ya'ni maxfiy kalit bermayotganingizni aytishingiz kerak. C# kompilyatori uchun buni /delaysign kompilyator kalitini ko'rsatib amalga oshirasiz. Visual Studio da loyihangiz xususiyatlarini ko'rsatib, Signing tabni bosib va keyin Delay Sign Only katakchasini belgilaysiz. Agar AL.exe dan foydalanayotgan bo'lsangiz, /delay[sign] buyruq qatori kalitini ko'rsatishingiz mumkin.

Kompilyator yoki AL.exe assemblyni kechiktirilgan imzolayotganini aniqlaganda, u assemblyning AssemblyDef manifest yozuvini yaratadi, bu assemblyning ochiq kalitini o'z ichiga oladi. Ochiq kalitning mavjudligi assemblyni GAC ga joylashtirishga imkon beradi. Shuningdek, u bu assemblyga havola qiluvchi boshqa assemblylar qurishga imkon beradi; havolaychi assemblylarda AssemblyRef metadata yozuvlarida to'g'ri ochiq kalit bo'ladi. Natija PE faylini yaratishda, RSA raqamli imzosi uchun joy qoldiriladi. (Yordamchi ochiq kalit hajmidan qancha joy kerakligini aniqlashi mumkin.) E'tibor bering, faylning tarkibi bu vaqtda xeshlanmaydi.

Shu nuqtada natija assemblida yaroqli imzo yo'q. Assemblyni GAC ga o'rnatishga urinish muvaffaqiyatsiz bo'ladi, chunki faylning tarkibining xeshlanmagan — fayl buzilgandek ko'rinadi. Assemblyni o'rnatishi kerak bo'lgan har bir mashinada tizimni assemblyning fayl yaxlitligini tekshirishdan to'xtatishingiz kerak. Buning uchun SN.exe yordamchisini -Vr buyruq qatori kaliti bilan ishlatasiz. SN.exe ni bu kalit bilan ishga tushirish shuningdek CLR ga assemblyning fayllari ish vaqtida yuklanganda xesh qiymatlarini tekshirmaslikni ham aytadi. Ichki jihatdan, SN ning -Vr kaliti assemblyning identifikatsiyasini quyidagi registr pastki kaliti ostiga qo'shadi: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification.

Muhim

Registr bilan ishlayotgan har qanday yordamchi dasturda, 64-bitli mashinada yordamchi dasturning 64-bitli versiyasini ishga tushirganingizga ishonch hosil qiling. Standart holda, 32-bitli yordamchi dasturlar C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools papkasiga, 64-bitli yordamchi dasturlar esa C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\x64 papkasiga o'rnatiladi.

Kechiktirilgan Imzolash Bosqichlari

Quyidagi ro'yxat kechiktirilgan imzolash texnikasini qo'llash uchun muhokama qilingan bosqichlarni umumlashtiradi:

  1. Ishlab chiqish jarayonida, faqat kompaniyangizning ochiq kalitini o'z ichiga olgan faylni oling va assemblyni /keyfile va /delaysign kompilyator kalitlari yordamida kompilyatsiya qiling.
    Buyruq qatori
    csc /keyfile:MyCompany.PublicKey /delaysign MyAssembly.cs
  2. Assemblyni qurib bo'lganingizdan so'ng, CLR assemblyning baytlariga ishonishi va xesh va taqqoslashni amalga oshirmasligi uchun quyidagi qatorni bajaring. Bu assemblyni GAC ga o'rnatishga (agar xohlasangiz) va boshqa assemblylarni qurishga, shuningdek assemblyni sinovdan o'tkazishga imkon beradi. E'tibor bering, bu buyruq qatorini har bir mashinada faqat bir marta bajarish kifoya; har safar assembly qurilganda bu bosqichni bajarish shart emas.
    Buyruq qatori
    SN.exe -Vr MyAssembly.dll
  3. Paketlash va deploy qilishga tayyor bo'lganingizda, kompaniyangizning maxfiy kalitini oling va quyidagi qatorni bajaring. Bu yangi versiyani GAC ga o'rnatishingiz mumkin, lekin 4-bosqichni bajarmaguncha o'rnatishga urinmang.
    Buyruq qatori
    SN.exe -Ra MyAssembly.dll MyCompany.PrivateKey
  4. Haqiqiy sharoitlarda sinovdan o'tkazish uchun, quyidagi buyruq qatorini bajarib tekshirishni qayta yoqing.
    Buyruq qatori
    SN.exe -Vu MyAssembly.dll

Ushbu bo'limning boshida men tashkilotlar o'z kalit juftliklarini smart karta kabi apparat qurilmasida saqlashini aytdim. Bu kalitlarni xavfsiz saqlash uchun, kalit qiymatlari hech qachon disk fayliga yozilmasligiga ishonch hosil qilishingiz kerak. Kriptografik xizmat provayderlari (CSP) bu kalitlarning joylashuvini abstraktlaydigan konteynerlarni taklif qiladi. Masalan, Microsoft kirilganda maxfiy kalitni apparat qurilmasidan oladigan konteynerga ega CSP dan foydalanadi.

Agar ochiq/maxfiy kalit juftligingiz CSP konteynerida bo'lsa, CSC.exe, AL.exe va SN.exe dasturlariga turli kalitlarni ko'rsatishingiz kerak bo'ladi: kompilyatsiya qilganingizda (CSC.exe), /keyfile o'rniga /keycontainer kalitini ko'rsating; bog'lash paytida (AL.exe), /keyfile o'rniga /keyname kalitini ko'rsating; Strong Name dasturidan (SN.exe) foydalanib kechiktirilgan imzolangan assemblyga maxfiy kalit qo'shganingizda, -R o'rniga -Rc kalitini ko'rsating. SN.exe CSP bilan operatsiyalarni bajarishga imkon beradigan qo'shimcha kalitlarni taklif qiladi.

Muhim

Kechiktirilgan imzolash assemblyni paketlashdan oldin biron boshqa operatsiya bajarishni xohlagan har qanday holatda ham foydali. Masalan, assemblyni obfuskator orqali o'tkazishni xohlashingiz mumkin. Assemblyni to'liq imzolganingizdan keyin obfuskatsiya qilib bo'lmaydi, chunki xesh qiymati noto'g'ri bo'ladi. Shuning uchun, agar assembly faylini obfuskatsiya qilish yoki boshqa post-build operatsiyasini bajarishni xohlasangiz, kechiktirilgan imzolashdan foydalaning, post-build operatsiyasini bajaring va keyin SN.exe ni -R yoki -Rc kaliti bilan ishga tushirib barcha xeshlash bilan imzolash jarayonini yakunlang.

Kuchli Nomlangan Assemblylarni Shaxsiy Deploy Qilish

Assemblylarni GAC ga o'rnatish bir qancha afzalliklarni taklif qiladi. GAC ko'p ilovalarga assemblylarni almashish imkonini beradi, bu esa jismoniy xotira iste'molini kamaytiradi. Bundan tashqari, assemblyning yangi versiyasini GAC ga deploy qilish va nashriyotchi siyosati orqali barcha ilovalarni yangi versiyaga yo'naltirish oson. GAC shuningdek assemblyning turli versiyalarini yon-ma-yon boshqarishni ta'minlaydi. Biroq, GAC odatda himoyalangan bo'lib, faqat administrator assemblyni unga o'rnatishi mumkin. Shuningdek, GAC ga o'rnatish oddiy nusxalash deploy qilish hikoyasini buzadi.

Garchi kuchli nomlangan assemblylar GAC ga o'rnatilishi mumkin bo'lsa ham, ular o'rnatilishi shart emas. Aslida, assemblylarni GAC ga faqat assembly ko'p ilovalar tomonidan almashilishi mo'ljallangan holda deploy qilish tavsiya etiladi. Agar assembly almashilishi mo'ljallanmagan bo'lsa, u shaxsiy deploy qilinishi kerak. Shaxsiy deploy qilish oddiy nusxalash deploy qilish hikoyasini saqlaydi va ilova va uning assemblylarini yaxshiroq izolyatsiya qiladi. Shuningdek, GAC yangi C:\Windows\System32 — umumiy fayllar uchun axlat qutisi bo'lishi mo'ljallanmagan. Buning sababi assemblylarning yangi versiyalari eski versiyalarni qayta yozmaydi; ular yon-ma-yon o'rnatiladi, disk joyini egallaydi.

Kuchli nomlangan assemblyni GAC yoki shaxsiy tarzda deploy qilishdan tashqari, kuchli nomlangan assemblyni kichik ilovalar guruhi biladigan ixtiyoriy papkaga ham deploy qilish mumkin. Masalan, siz kuchli nomlangan assemblyni almashmoqchi bo'lgan uchta ilovani ishlab chiqarayotgan bo'lishingiz mumkin. O'rnatish paytida siz to'rtta papka yaratishingiz mumkin: har bir ilova uchun bittadan va almashmoqchi bo'lgan assembly uchun qo'shimcha bir papka. Har bir ilovani o'z papkasiga o'rnatganingizda, umumiy assemblyning yo'lini ko'rsatuvchi XML konfiguratsiya faylini ham o'rnating va umumiy assemblining codeBase elementini ishlatib yo'lni belgilang. Ish vaqtida CLR kuchli nomlangan assemblyning papkasiga qarashni biladi. Ma'lumot uchun, bu texnika kamdan-kam ishlatiladi va biroz taqiqlanadi, chunki biror ilova assemblyning fayllarini o'chirib tashlashni nazorat qilmaydi.

Eslatma

Konfiguratsiya faylining codeBase elementi aslida URL ni identifikatsiya qiladi. Bu URL foydalanuvchining mashinasidagi istalgan papkaga yoki veb-manzilga ishora qilishi mumkin. Veb-manzil bo'lsa, CLR faylni avtomatik yuklab oladi va foydalanuvchining yuklab olish keshida saqlaydi (C:\Users\FoydalanuvchiNomi\Local Settings\Application Data\Assembly quyi papkasida). Kelajakda havola qilinganda, CLR yuklangan faylning vaqt tamg'asini ko'rsatilgan URL dagi faylning vaqt tamg'asi bilan solishtiradi. URL dagi fayl yangi bo'lsa, CLR faylning yangi versiyasini yuklab oladi. Oldindan yuklangan fayl yangi bo'lsa, CLR uni yuklaydi va faylni qayta yuklamaydi (unumdorlikni yaxshilaydi).

Runtime Tur Havolalarini Qanday Hal Qiladi

2-bobning boshida biz quyidagi manba kodini ko'rgan edik:

C#
public sealed class Program {
    public static void Main() {
        System.Console.WriteLine("Hi");
    }
}

Bu kod assemblyga kompilyatsiya qilinadi va quriladi, masalan Program.exe. Bu ilovani ishga tushirganingizda, CLR yuklanadi va ishga tushiriladi. Keyin CLR assemblyning CLR sarlavhasini o'qiydi va ilovaning kirish nuqtasi metodini (Main) identifikatsiya qiluvchi MethodDefToken ni qidiradi. MethodDef metadata jadvalidan metod uchun fayl ichidagi IL kodining ofseti topiladi va JIT-kompilyatsiya qilinadi — bu jarayonga kodning tur xavfsizligi uchun tekshirilishi ham kiradi. Keyin native kod bajarilishni boshlaydi.

Quyida Main metodi uchun IL kod ko'rsatilgan. Bu chiqishni olish uchun men ILDasm.exe ni ishga tushirdim, View menyusining Show Bytes menyu elementini tanladim va keyin daraxt ko'rinishida Main metodini ikki marta bosdim.

IL kod (ILDasm chiqishi)
.method public hidebysig static void  Main() cil managed
// SIG: 00 00 01
{
  .entrypoint
  // Method begins at RVA 0x2050
  // Code size       11 (0xb)
  .maxstack  8
  IL_0000:  /* 72   | (70)000001       */   ldstr      "Hi"
  IL_0005:  /* 28   | (0A)000003       */   call       void [mscorlib]System.Console::WriteLine(string)
  IL_000a:  /* 2A   |                  */   ret
} // end of method Program::Main

CLR bu kodni JIT-kompilyatsiya qilganda, turlar va a'zolarga barcha havolalarni aniqlaydi va ularning aniqlayici assemblylarini yuklaydi (agar hali yuklanmagan bo'lsa). Ko'rib turganingizdek, oldingi IL kodda System.Console.WriteLine ga havola bor. Aniqroq aytganda, IL call instruktsiyasi 0A000003 metadata tokeniga havola qiladi. Bu token 3-raqamli yozuvni (jadval 0A) MemberRef metadata jadvalida identifikatsiya qiladi. CLR bu MemberRef yozuvini ko'rib chiqadi va uning maydonlaridan biri TypeRef jadvalidagi yozuvga (System.Console turi) ishora qilishini ko'radi. TypeRef yozuvidan CLR AssemblyRef yozuviga yo'naltiriladi: "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089". Bu nuqtada CLR qaysi assemblyni topishi kerakligini biladi.

Tur Havolalarini Hal Qilish Jarayoni

Havolalangan turni hal qilganda, CLR turni uchta joydan birida topishi mumkin:

  • Bir xil fayl — bir xil fayldagi turga kirish kompilyatsiya vaqtida aniqlanadi (ba'zan erta bog'lanish deb ataladi). Tur to'g'ridan-to'g'ri fayldan yuklanadi va bajarilish davom etadi.
  • Boshqa fayl, bir xil assembly — Runtime havolalangan faylning assemblyning ModuleRef jadvalida haqiqatan ham mavjudligini ta'minlaydi. Keyin runtime assemblyning manifest fayli yuklangan papkada qidiradi. Fayl yuklanadi, uning xesh qiymati yaxlitligini ta'minlash uchun tekshiriladi, turning a'zosi topiladi va bajarilish davom etadi.
  • Boshqa fayl, boshqa assembly — Havolalangan tur boshqa assemblyning faylida bo'lganda, runtime havolalangan assemblyning manifestini o'z ichiga olgan faylni yuklaydi. Agar bu fayl turni o'z ichiga olmasa, tegishli fayl yuklanadi. Turning a'zosi topiladi va bajarilish davom etadi.
Eslatma

ModuleDef, ModuleRef va FileDef metadata jadvallari fayllarga faylning nomi va kengaytmasi yordamida murojaat qiladi. Biroq, AssemblyRef metadata jadvali assemblylarga kengaytmasiz fayl nomi bilan murojaat qiladi. Assemblyga bog'lanishda tizim avtomatik ravishda faylni topishga urinayotganda .dll va .exe fayl kengaytmalarini qo'shadi — 2-bobdagi "Oddiy Administrativ Boshqarish (Konfiguratsiya)" bo'limida aytilganidek papkalarni tekshirish orqali.

Agar turni hal qilishda biron xato yuz bersa — fayl topilmasa, fayl yuklanmasa, xesh mos kelmasa va hokazo — tegishli istisno tashlanadi.

Eslatma

Agar xohlasangiz, kodingiz System.AppDomain ning AssemblyResolve, ReflectionOnlyAssemblyResolve va TypeResolve hodisalariga callback metodlarini ro'yxatdan o'tkazishi mumkin. Callback metodlaringizda siz bog'lanish muammosini hal qiluvchi va ilovaning istisno tashlamasdan ishlashini davom ettiradigan kodni bajarishingiz mumkin.

Oldingi misolda CLR System.Console chaqiruvchidan boshqa assemblyda amalga oshirilganligini aniqlaydi. CLR assembly faylini qidirishi va manifest o'z ichiga olgan PE faylni yuklashi kerak. Manifest keyin havolalangan turni amalga oshiradigan PE faylni aniqlash uchun skanerlanadi. Agar manifest fayli havolalangan turni o'z ichiga olsa, hammasi yaxshi. Agar tur assemblyning boshqa fayllaridan birida bo'lsa, CLR boshqa faylni yuklaydi va turni topish uchun uning metadatasini skanerlaydi. Keyin CLR turni ifodalaydigan ichki ma'lumotlar tuzilmalarini yaratadi va JIT kompilyator Main metodi uchun kompilyatsiyani yakunlaydi. Nihoyat, Main metodi bajarilishni boshlashi mumkin.

Muhim

Qat'iy qilib aytganda, yuqorida tasvirlangan misol 100 foiz to'g'ri emas. .NET Framework bilan birga kelmagan assemblydagi metod va turlarga havolalar uchun muhokama to'g'ri. Biroq, .NET Framework assemblylari (MSCorLib.dll ni o'z ichiga olgan) ishlayotgan CLR versiyasiga chambarchas bog'langan. .NET Framework assemblylariga havola qiluvchi har qanday assembly har doim CLR versiyasiga mos keladigan versiyaga bog'lanadi. Bu birlashtirish (unification) deb ataladi va Microsoft buni barcha .NET Framework assemblylarini CLR ning ma'lum versiyasi bilan sinov o'tkazganligi uchun amalga oshiradi; shuning uchun kod to'plamini birlashtirish ilovalar to'g'ri ishlashini ta'minlashga yordam beradi.

Demak, oldingi misolda System.Console ning WriteLine metodiga havola assemblyning AssemblyRef metadata jadvalida MSCorLib.dll ning qaysi versiyasiga havola qilinganidan qat'iy nazar, CLR versiyasiga mos keladigan MSCorLib.dll versiyasiga bog'lanadi.

GAC da assemblyni qidirishda yana bir noziklik bor. CLR uchun barcha assemblylar nom, versiya, madaniyat va ochiq kalit bo'yicha identifikatsiya qilinadi. Biroq, GAC assemblylarni nom, versiya, madaniyat, ochiq kalit va CPU arxitekturasi bo'yicha identifikatsiya qiladi. GAC da assembly qidirganda, CLR ilova qaysi turdagi jarayonda ishlayotganini aniqlaydi: 32-bitli x86 (mumkin WoW64 texnologiyasi yordamida), 64-bitli x64 yoki 32-bitli ARM. Keyin GAC da assembly qidirganda, CLR avval CPU arxitekturasi-ga xos assemblyni qidiradi. Agar mos keladigan assembly topilmasa, u keyin CPU-agnostik assemblyni qidiradi.

Kengaytirilgan Administrativ Boshqarish (Konfiguratsiya)

2-bobdagi "Oddiy Administrativ Boshqarish (Konfiguratsiya)" bo'limida men administratorning CLR assemblylarni qidirish va ularga bog'lanish usullariga qanday ta'sir o'tkazishi mumkinligi haqida qisqacha kirish berdim. O'sha bo'limda men havolalangan assemblyning fayllarini ilovaning bazaviy papkasining quyi papkasiga qanday ko'chirish va CLR ilovaning XML konfiguratsiya faylidan ko'chirilgan fayllarni topish uchun qanday foydalanishni ko'rsatdim.

2-bobda faqat probing elementining privatePath atributini muhokama qildim. Endi men ushbu bo'limda boshqa XML konfiguratsiya fayli elementlarini ko'rib chiqaman.

Konfiguratsiya Fayli Elementlari

Quyida XML konfiguratsiya faylining misoli keltirilgan:

XML konfiguratsiya fayli
<?xml version="1.0"?>
<configuration>
   <runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
         <probing privatePath="AuxFiles;bin\subdir" />

         <dependentAssembly>
            <assemblyIdentity name="SomeClassLibrary"
               publicKeyToken="32ab4ba45e0a69a1" culture="neutral"/>

            <bindingRedirect
               oldVersion="1.0.0.0" newVersion="2.0.0.0" />

            <codeBase version="2.0.0.0"
               href="http://www.Wintellect.com/SomeClassLibrary.dll" />
         </dependentAssembly>

         <dependentAssembly>
            <assemblyIdentity name="TypeLib"
               publicKeyToken="1f2e74e897abbcfe" culture="neutral"/>

            <bindingRedirect
               oldVersion="3.0.0.0-3.5.0.0" newVersion="4.0.0.0" />

            <publisherPolicy apply="no" />
         </dependentAssembly>

      </assemblyBinding>
   </runtime>
</configuration>

Bu XML fayl CLR ga boy ma'lumotlar beradi. Mana u nima deydi:

  • probing elementi — zaif nomlangan assemblyni topishga uringanda ilovaning bazaviy papkasining AuxFiles va bin\subdir quyi papkalarini ko'rib chiqadi. Kuchli nomlangan assemblylar uchun CLR GAC ga yoki codeBase elementi ko'rsatgan URL ga qaraydi. CLR ilovaning shaxsiy yo'llarida kuchli nomlangan assemblyni faqat codeBase elementi ko'rsatilmagan taqdirdagina qidiradi.
  • Birinchi dependentAssembly, assemblyIdentity va bindingRedirect elementlari32ab4ba45e0a69a1 ochiq kalit tokenini boshqaruvchi tashkilot tomonidan nashr etilgan madaniyatga neytral SomeClassLibrary assemblining 1.0.0.0 versiyasini topishga uringanda, o'sha assemblyning 2.0.0.0 versiyasini toping.
  • codeBase elementi32ab4ba45e0a69a1 ochiq kalit tokenini boshqaruvchi tashkilot tomonidan nashr etilgan madaniyatga neytral SomeClassLibrary assemblining 2.0.0.0 versiyasini topishga uringanda, uni quyidagi URL dan topishga urinadi: www.Wintellect.com/SomeClassLibrary.dll. Garchi 2-bobda aytilmagan bo'lsa ham, codeBase elementi zaif nomlangan assemblylar bilan ham ishlatilishi mumkin. Bu holda assemblyning versiya raqami e'tiborsiz qoldiriladi va tashlab ketilishi kerak. Shuningdek, codeBase URL ilovaning bazaviy papkasi ostidagi papkaga ishora qilishi kerak.
  • Ikkinchi dependentAssembly, assemblyIdentity va bindingRedirect elementlari1f2e74e897abbcfe ochiq kalit tokenini boshqaruvchi tashkilot tomonidan nashr etilgan madaniyatga neytral TypeLib assemblining 3.0.0.0 dan 3.5.0.0 gacha (shu jumladan) versiyasini topishga uringanda, o'sha assemblyning 4.0.0.0 versiyasini toping.
  • publisherPolicy elementi — TypeLib assemblyni ishlab chiqaruvchi tashkilot nashriyotchi siyosat faylini deploy qilgan bo'lsa (keyingi bo'limda tasvirlanadi), CLR bu faylni e'tiborsiz qoldirishi kerak.

Metodni kompilyatsiya qilganda, CLR havolalangan turlar va a'zolarni aniqlaydi. Bu ma'lumotdan foydalanib, runtime havolaychi assemblyning AssemblyRef jadvaliga qarab, chaqiruvchi assembly qurilganda dastlab havolalangan assemblyni topadi. CLR keyin ilovaning konfiguratsiya faylida assembly/versiyani ko'rib chiqadi va versiya raqami yo'naltirishlarini qo'llaydi; CLR endi bu assembly/versiyani qidirmoqda.

Agar publisherPolicy elementining apply atributi yes ga o'rnatilgan bo'lsa — yoki element umuman tashlab ketilgan bo'lsa — CLR yangi assembly/versiya uchun GAC ni tekshiradi va assemblyning nashriyotchisi kerak deb hisoblagan versiya raqami yo'naltirishlarini qo'llaydi; CLR endi bu assembly/versiyani qidirmoqda. Keyin CLR mashinaning Machine.config faylida assembly/versiyani ko'rib chiqadi va u yerdagi har qanday versiya raqami yo'naltirishlarini qo'llaydi.

Bu nuqtada CLR yuklanishi kerak bo'lgan assemblyning versiyasini biladi va u assemblyni GAC dan yuklashga harakat qiladi. Agar assembly GAC da bo'lmasa va codeBase elementi bo'lmasa, CLR assemblyni 2-bobda tasvirlaganimdek tekshirish (probing) usuli bilan qidiradi. Agar konfiguratsiya fayl oxirgi yo'naltirish shuningdek codeBase elementini o'z ichiga olsa, CLR assemblyni codeBase elementining ko'rsatilgan URL dan yuklashga harakat qiladi.

Ushbu konfiguratsiya fayllaridan foydalanib, administrator CLR qaysi assemblyni yuklashini haqiqatan ham nazorat qilishi mumkin. Agar ilova xato bilan duch kelayotgan bo'lsa, administrator noto'g'ri assembly nashriyotchisi bilan bog'lanishi mumkin. Nashriyotchi administratorga o'rnatishi mumkin bo'lgan yangi assemblyni yuborishi mumkin. Standart holda, CLR bu yangi assemblyni yuklamaydi, chunki allaqachon qurilgan assemblylar unga havola qilmaydi. Biroq, administrator ilovaning XML konfiguratsiya faylini CLR ga yangi assemblyni yuklashni buyurish uchun o'zgartirishi mumkin.

Agar administrator mashinadagi barcha ilovalarning yangi assemblyni yuklashini xohlasa, administrator o'sha mashinaning Machine.config faylini o'zgartirishi mumkin va CLR har qanday ilova eski assemblyga havola qilganda yangi assemblyni yuklaydi.

Agar yangi assembly asl xatoni tuzatmasa, administrator bog'lanish yo'naltirish qatorlarini konfiguratsiya faylidan o'chirib tashlashi mumkin va ilova avvalgidek ishlashni davom ettiradi. Tizim metadatada qayd etilgan assembly versiyasiga aniq mos kelmaydigan assemblyni ishlatishga ruxsat berishini e'tibor bering. Bu qo'shimcha moslashuvchanlik juda qulay.

Nashriyotchi Siyosati (Publisher Policy Control)

Oldingi bo'limda tasvirlangan stsenariyda assembly nashriyotchisi shunchaki assemblyning yangi versiyasini administratorga yubordi va administrator qo'lda ilovaning yoki mashinaning XML konfiguratsiya fayllarini tahrirladi. Umuman olganda, nashriyotchi assemblydagi xatoni tuzatganda, yangi assemblyni paketlash va barcha foydalanuvchilarga tarqatishning oson usulini xohlaydi. Lekin nashriyotchiga har bir foydalanuvchining CLR ga eski assembly versiyasi o'rniga yangi assembly versiyasini ishlatishni aytishning usuli ham kerak. Agar har bir foydalanuvchi o'zining ilovasi yoki mashinasining XML konfiguratsiya faylini o'zgartirsa bo'ladi, lekin bu juda noqulay va xatolarga moyil. Nashriyotchiga kerak bo'lgan narsa — yangi assembly foydalanuvchining kompyuteriga o'rnatilganda siyosat ma'lumotlarini yaratish usuli.

Aytaylik, siz assembly nashriyotchisisiz va assemblyning ba'zi xatolarni tuzatuvchi yangi versiyasini yaratdingiz. Yangi assemblyni barcha foydalanuvchilaringizga jo'natish uchun paketlayotganingizda, siz XML konfiguratsiya faylini ham yaratishingiz kerak. Bu konfiguratsiya fayl avval gaplashgan konfiguratsiya fayllariga juda o'xshash. Mana SomeClassLibrary.dll assembly uchun misol fayl (SomeClassLibrary.config deb nomlangan):

SomeClassLibrary.config (nashriyotchi siyosati)
<configuration>
   <runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
         <dependentAssembly>

            <assemblyIdentity name="SomeClassLibrary"
               publicKeyToken="32ab4ba45e0a69a1" culture="neutral"/>

            <bindingRedirect
               oldVersion="1.0.0.0" newVersion="2.0.0.0" />

            <codeBase version="2.0.0.0"
               href="http://www.Wintellect.com/SomeClassLibrary.dll"/>

         </dependentAssembly>
      </assemblyBinding>
   </runtime>
</configuration>

Albatta, nashriyotchilar faqat o'zlari yaratgan assemblylar uchun siyosat o'rnatishi mumkin. Bundan tashqari, bu yerda ko'rsatilgan elementlar nashriyotchi siyosat konfiguratsiya faylida ko'rsatilishi mumkin bo'lgan yagona elementlardir; masalan, probing yoki publisherPolicy elementlarini ko'rsata olmaysiz.

Bu konfiguratsiya fayl CLR ga SomeClassLibrary assemblining 1.0.0.0 versiyasiga havola qilingan har qanday vaqtda 2.0.0.0 versiyasini yuklashni aytadi. Endi siz, nashriyotchi, bu nashriyotchi siyosat konfiguratsiya faylini o'z ichiga olgan assembly yaratishingiz mumkin. Nashriyotchi siyosat assemblysini AL.exe ni ishga tushirib yaratasiz:

Buyruq qatori
AL.exe /out:Policy.1.0.SomeClassLibrary.dll
       /version:1.0.0.0
       /keyfile:MyCompany.snk
       /linkresource:SomeClassLibrary.config

AL.exe ning buyruq qatori kalitlarining ma'nosini tushuntiraman:

  • /out — bu kalit AL.exe ga Policy.1.0.SomeClassLibrary.dll deb nomlangan yangi PE fayl yaratishni aytadi, bu fayl manifestdan boshqa hech narsani o'z ichiga olmaydi. Bu assemblyning nomi juda muhim. Nomning birinchi qismi Policy CLR ga bu assembly nashriyotchi siyosat ma'lumotlarini o'z ichiga olishini aytadi. Nomning ikkinchi va uchinchi qismlari 1.0 bu nashriyotchi siyosat assemblisi major va minor versiyasi 1.0 bo'lgan har qanday SomeClassLibrary assembly versiyasiga tegishli ekanligini aytadi. Nashriyotchi siyosatlari faqat assemblyning major va minor versiya raqamlariga qo'llaniladi; alohida build yoki revision uchun nashriyotchi siyosat yarata olmaysiz. Nomning to'rtinchi qismi SomeClassLibrary bu nashriyotchi siyosatining qaysi assemblyga tegishli ekanligini ko'rsatadi. Beshinchi va oxirgi qism dll shunchaki natija assembly fayliga berilgan kengaytma.
  • /version — bu kalit nashriyotchi siyosat assemblisining versiya raqamini identifikatsiya qiladi; bu versiya raqami SomeClassLibrary assemblisi bilan hech qanday aloqasi yo'q. Nashriyotchi siyosat assemblylari ham versiyalanishi mumkin. Bugun nashriyotchi SomeClassLibrary ning 1.0.0.0 versiyasini 2.0.0.0 versiyasiga yo'naltiruvchi nashriyotchi siyosat yaratishi mumkin. Kelajakda nashriyotchi SomeClassLibrary ning 1.0.0.0 versiyasini 2.5.0.0 versiyasiga yo'naltirishni xohlashi mumkin. CLR bu versiya raqamidan foydalanib nashriyotchi siyosat assemblisining eng so'nggi versiyasini tanlashni biladi.
  • /keyfile — bu kalit AL.exe ga nashriyotchi siyosat assemblisini nashriyotchining ochiq/maxfiy kalit juftligi yordamida imzolashga olib keladi. Bu kalit juftligi SomeClassLibrary assemblining barcha versiyalari uchun ishlatiladigan kalit juftligiga mos kelishi kerak. Axir, CLR aynan shu tarzda bir xil nashriyotchi SomeClassLibrary assemblisini ham, bu nashriyotchi siyosat faylini ham yaratganligini biladi.
  • /linkresource — bu kalit AL.exe ga XML konfiguratsiya faylini assemblyning alohida fayli sifatida ko'rishni aytadi. Natija assembly ikki fayldan iborat bo'lib, ikkalasi ham SomeClassLibrary ning yangi versiyasi bilan birga paketlanishi va deploy qilinishi kerak. Aytgancha, siz AL.exe ning /embedresource kalitini ishlatib XML konfiguratsiya faylini assembly fayliga joylshtira olmaysiz, chunki CLR XML faylni o'zining alohida faylida bo'lishini talab qiladi.

Bu nashriyotchi siyosat assembly qurilganidan so'ng, u yangi SomeClassLibrary.dll assembly fayli va foydalanuvchilarga deploy qilinishi mumkin. Nashriyotchi siyosat assembly GAC ga o'rnatilishi kerak. SomeClassLibrary assembly ham GAC ga o'rnatilishi mumkin, lekin shart emas. U ilovaning bazaviy papkasiga yoki codeBase URL bilan aniqlangan boshqa papkaga deploy qilinishi mumkin.

Muhim

Nashriyotchi siyosat assemblysini faqat assemblyning yangilanishi yoki xizmat to'plami versiyasini deploy qilayotganda yarating. Ilovaning yangi o'rnatilishida hech qanday nashriyotchi siyosat assemblylari o'rnatilmasligi kerak.

Nashriyotchi siyosati haqida oxirgi bir nuqta. Aytaylik, nashriyotchi siyosat assemblysini tarqatadi va biron sabab bilan yangi assembly avvalgisiga qaraganda ko'proq xato keltirib chiqaradi. Bu holda administrator CLR ga nashriyotchi siyosat assemblysini e'tiborsiz qoldirishni aytishni xohlaydi. Buning uchun administrator ilovaning konfiguratsiya fayliga quyidagi publisherPolicy elementini qo'shishi mumkin:

publisherPolicy elementi
<publisherPolicy apply="no"/>

Bu element <assemblyBinding> elementining bola elementi sifatida joylashtirilishi mumkin (barcha assemblylarga ta'sir qiladi) yoki ilovaning konfiguratsiya faylida <dependentAssembly> elementining bola elementi sifatida joylashtirilishi mumkin (faqat muayyan assemblyga ta'sir qiladi). CLR ilovaning konfiguratsiya faylini qayta ishlaganda, GAC da nashriyotchi siyosat assemblysini tekshirmasligini ko'radi. Shunday qilib, CLR eski assembly versiyasidan foydalanishni davom ettiradi. E'tibor bering, CLR hali ham Machine.config faylida ko'rsatilgan har qanday siyosatni tekshiradi va qo'llaydi.

Muhim

Nashriyotchi siyosat assembly — nashriyotchining assemblyning turli versiyalari o'rtasidagi mos kelish haqida bayonot berish usuli. Agar assemblyning yangi versiyasi avvalgi versiyaga mos bo'lishi mo'ljallanmagan bo'lsa, nashriyotchi nashriyotchi siyosat assemblysini yaratmasligi kerak. Umuman olganda, assemblyning xatoni tuzatuvchi yangi versiyasini qurayotganingizda nashriyotchi siyosat assemblysidan foydalaning. Yangi versiyani assemblyning orqaga qarab muvofiqligi uchun sinov o'tkazishingiz kerak. Boshqa tomondan, agar assemblyga yangi xususiyatlar qo'shayotgan bo'lsangiz, assemblyni oldingi versiya bilan hech qanday aloqasi yo'q deb hisoblashingiz kerak va nashriyotchi siyosat assemblysini jo'natmasligingiz kerak. Bundan tashqari, bunday assembly bilan orqaga qarab muvofiqlik sinovini o'tkazish kerak emas.