.NET Assembly
Assembly nedir? Sorusuna cevap vermeden önce managed module nedir? sorusuna cevap verelim ilk önce.
Managed Module nedir?
Managed module, bir .NET uygulamasının en küçük bileşenidir ve IL (Intermediate Language) olarak bilinen ara dile derlenmiş halidir. Bir managed module, derlenmiş kod(IL), kaynak dosyaları(image,json,pdf vs.), metadata ve bazı ek bilgiler içerir. Bu managed module, CLR(Common language runtime) tarafından yönetilir ve çalışma zamanında yönetilen bir ortamda çalışır. Bu ortam, kodun daha güvenli, daha hızlı ve daha güvenilir bir şekilde çalışmasını sağlar.
Şimdi “assembly nedir?” sorusua cevap verebiliriz.
Assembly Nedir?
Assembly ise bir veya birden fazla managed modül içeren küçük, paylaşılan ve kod tekrarını önleyen paketlerdir. Assembly’ler, uygulamanın çalıştırılabilmesi için gerekli tüm bilgileri içerir. Assembly, bir programın derlendiği ve yürütülebilir kodun depolandığı temel pakettir. .Net içinde, bir assembly genellikle bir .dll veya .exe dosyasıdır. Ve bu dosya içinde bir veya birden fazla sınıf, arayüz, yapı ve diğer program bileşenleri barındırır. Her bir assembly, birbirinden bağımsız birimler olarak düşünülebilir ve farklı projelerde veya uygulamalarda kullanılabilir. Ayrıca, .Net’teki birçok özellik, assembly’lerin kullanımına dayanır. Bu nedenle, assembly konusu .Net’teki geliştirme süreci için oldukça önemlidir.
İki Farklı Assembly ve İki Farklı Deploy
CLR, iki çeşit assembly destekler. Bunlar: zayıf isimli assembly ile güçlü isimli assembly. Bu arada Microsoftun dökümantasyonunda böyle bir isimlendirme yok. Fakat konuyu daha iyi anlayabilmek için “CLR via CSharp” kitabının yazarı olan Jeffrey Richter kitabında bu isimlendirmeyi koymuştur.
Zayıf isimli assembly ile güçlü isimli assembly yapısal olarak birebir aynıdır. Ikiside portable executable PE(taşınabilir çalıştırılabilir) dosya formatı, PE32+ header, CLR header, metadata, manifest tabloları ve IL(Intermediate language) kodu içerir. Aralarındaki tek fark ise güçlü isimli assembly, yayıncının public ve private key ile imzalanmış olmasıdır. Bu key ile imzalama sonucunda artık bu assembly bütün .NET ortamında paylaşılan assembly’ler içinde tekildir, güvenlidir ve versiyonlanmıştır. Artık kullanıcının makinesine veya internet ortamında paylaşılmaya hazırdır. Artık CLR bu assembly’nin güvenli olduğunu bilir.
Bir assembly iki farklı şekilde deploy edilir: Özel(privately) veya genel(globally). Özel assembly deployu, assembly’i uygulamanın bulunduğu klasöre veya alt kalsörlere yüklenmesidir. Zayıf isimli(imzasız) assemby’ler sadece özel (privately) olarak yüklenebilir. Genel assembly yüklemesi, CLR assembly’i ararken hemen bulabileceği bir yere yükler. Bu yer GAC’tır. GAC’ı aşağıda detaylı bir şekilde anlatacağım. Güçlü isimli assembly’ler hem özel hemde genel olarak deploy edilebilir.
Assembly’e Güçlü Bir İsim Vermek
Diyelim ki iki tane uygulama bir tane assembly’i yüklemeye çalışıyor. Bu assembly’de CLR’in bildiği bir yerde olsun. Burada şöyle bir durum ortaya çıkabilir. İki farklı firma 2 farklı assembly geliştirip aynı ismi verdiler ve bu assembly’ler CLR’in bildiği bir yere kopyalandılar. Son gelen assembly ilk gelen assembly ezeceğinden dolayı, ilk assembly’i kullanan uygulama doğru çalışmayacaktır. Bundan dolayı Window’ta bugün .dll cehennemi(.dll’s hell) dedikleri bir problem vardır. Çünkü paylaşılan bütün .dll’ler System32 klasöründe bulunuyor.
Açık bir şekilde assembly ismini farklı yapmak yeterli gelmeyecektir. O yüzden CLR’in assembly’leri tekil olarak algılaması için farklı bir mekanizma vardır. Bu mekanizmaya güçlü isim verme mekanizması denir. Güçlü bir assembly adı oluşturmak için dört farklı parametreden yaralanılır. Bunlar: dosya ismi(uzantısız), version numarası, culture identity ve public key anahtarıdır. Public key anahtarı değeri çok uzun bir degerdir bu yüzden, o değerin hash’lenmiş hali kullanılır. Bu hash değerine public key token denir. Aşağıdaki assembly kimlikleri verilen farklı dört assembly gösterilmektedir.
“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”
Birinci parametrede MyType olarak verilen dosya adı MyType.exe veya MyType.dll(uzantı bilgisi tutulmaz) olabilir. Firma, adı MyType , versiyon numarası 1.0.8.1234.0 ve culture olarak neutral olan bir assembly’ye kendi imzasını vererek paylaşabilir. Faklı bir firmada, aynı isim, aynı versiyon ve aynı culture ile assebmly oluşturabilir. Ama kendi key değeri ile imzaladığı için o assembly farklı olacaktır. Ve CLR bu assembly’leri farklı algılayacaktır. Eğer bir firma assembly’sinin tek olmasını istiyorsa public ve private key ile imzalaması gerekir. Çünkü public ve private key değerleri aynı olan iki firma yoktur.
Zayıf isimli assembly’nin versiyon numarası ve culture bilgisi direk manifest dosyasının içinde bulunur. Fakat CLR assembly’i alt kalsörlerde ararken versiyon numarasını görmezden gelip sadece culture değerine bakar. Çünkü zayıf isimli assembly’ler her zaman özel deploy edilir ve uygulamananın alt klasörlerinde bulunur.
The Global Assembly Cache(GAC)
Eğer bir assembly birden fazla uygulamada kullanılıyorsa, bu assembly iyi bilinen bir klasörde olması lazım. Ve CLR bu klasöre otomatik bakarak assembly’i yükler. Bu klasöre GAC(Global Assembly Cache) denir. GAC’in yeri kurulan SDK’nın versiyonuna göre farklılık göstermektedir. Ama genellikle burada “%SystemRoot%\Microsoft.NET\Assembly” bulunur. GAC yapısaldır ve bir sürü alt klasör bulunur. Bu alt klasörleri oluşturan bir algoritma vardır. Bu yüzden buradaki alt kalsörlerin yerini değiştirmeyiniz. Ve elle oraya assembly koymayınız. Bunu da illaki yapacaksnız ve ihtiyacınız varsa GACUtil.exe kullanabilirsiniz. GACUtil.exe oradaki alt klasörlerin isimlerini algoritmaya göre verecektir.
Friend Assemblies
Burada şöyle bir senaryo düşünelim. Elimizde iki tane assemblyA ve assemblyB olsun. Diyelim ki assemblyB assemblyA’daki bazı tipleri kullanıyor olsun. İşte burada assemblyB’nin assemblyA’daki internal olarak tanımlanmış tiplere(public yapmadan sedece assemblyB’nin erişimine açmak) erişebilmesi için assembyA’nın assemblyB’yi friend assembly olarak tanımlaması gerekiyor. Eğer böyle bir tanım yapılmışsa assemblyB assemblyA’nın arkadaşıdır denir.
Assembly konusu, .Net geliştirme sürecinde oldukça önemli bir konudur. Bir programın derlendiği ve yürütülebilir kodun depolandığı temel birim olan assembly, programlama dilleri arasındaki uyumluluğu sağlayan ve farklı projelerde veya uygulamalarda kullanılabilen bir birimdir. Ayrıca, .Net içinde birçok özellik, assembly’lerin kullanımına dayanır. Bu nedenle, assembly konusunu anlamak, .Net içindeki geliştirme sürecini daha verimli ve etkili hale getirebilir. Umarım bu makale, assembly konusu hakkında daha fazla bilgi edinmenize ve .Net geliştirme sürecinde daha iyi bir yolculuk yapmanıza yardımcı olmuştur.
Yararlanılan kaynaklar:
Microsoft CLR via C# Fourth Edition kitabı.