.NETin Temelleri -3

.NETin Temelleri 3 .NETin Temelleri 3

Assembly’ler üzerine 

Bir önceki yazıda assembly’lerin temellerini ve .NET altındaki temel işlevlerini görmüştük. Her ne kadar alışılmış olandan çok daha basit bir yapıyı bizlere sağlasa da assembly’ler kendileri o derecede basit değiller :) Daha doğrusu .NET üzerinde kesin bir hakimiyet ile çalışmak isteyenlerin bu konuyu biraz daha detaylı incelemesi gerekiyor.Şimdi birlikte assembly’ler üzerine daha detaylı bir incelemeye başlayalım

Public ve Private assembly’ler. 

Assembly’ler .NET tarafından oluşturulduklarında, eğer özellikle belirtilmemişse, private olarak oluşturulurlar. Private ne demek peki ? Private assembly ile kast ettiğimiz şey, sadece bir uygulama tarafından kullanılmak üzere tasarlanmış olan assembly  oluyor.

Public assemby’ler ise bir sistemde bulundukları sürece tüm sistemdeki yazılımların kullanabileceği şekilde çalışıyorlar. Bu konulara çok daha detaylı olarak gireceğiz, şimdi isterseniz, assembly’lerin genel olarak sağladığı diğer olanaklara değinelim. 

Assembly’ler kullanılan türler için birer kap görevi görür. Bu ne demek oluyor şimdi ? Şu demek oluyor: eğer ismi A olan bir assembly içinde typeX isimli bir yapınız varsa, ve aynı isimle B assembly’si içinde bir başka yapı tanımlarsanız, A ve B assembly’leri farklı isim uzayları sağladığı için, isim çakışmaları olmaksızın bu aynı isimli ama farklı iki türü kullanabilirsiniz.

Assembly’ler versiyon bilgisi taşırlar.Yani oluşturduğumuz bir assembly için versiyon numarası belirleyebiliriz. Bunu bize faydası ne olabilir peki  ?

Klasik COM bileşenleri kullanırken, bir dll’in 1.0 versiyonunda kullanıcıya bir interface sağladıysanız, bunu ilerideki versiyonlarda da sürdürmek zorundasınızdır. Çünkü siz a.dll isimli dosyanın yeni bir versiyonunu çıkarınca eskisini bu yeni versiyonla değiştirmelisiniz. Bu durumda varolan ve a.dll içindeki özellikleri kullanan programların çakılmasını engellemek için yeni versiyonda da bu özellikler aynen korunmalıdır. Klasik COM’daki bir başka sorun da bileşenler arasındaki ilişkileri tanımlayan bir mekanizmanın bulunmamasıdır. Yani bir bileşenin ihtiyaç duyduğu diğer bileşenleri belirtme imkanı yoktur. Bu sebeple, tek başına önemsiz görünen bir bileşende yapılan bir değişiklik, ( veya en basitinden o bileşenin silinmesi ) ona bağlı tüm bileşenlerde sorun çıkaracaktır. 

Oysa assembly’ler bu sorunların tümünü ortadan kaldırıyor. Her assembly, içerdiği tüm elamanlar için geçerli olan bir versiyon numarasına sahip. Artı daha önce bahsettiğimiz manifest sayesinde, bir assembly için gerekli olan tüm bileşenler listelenebiliyor.Bahsettiğimiz bu versiyon numarası kullanıcı dostu bir metin (“benim assembly’im” gibi ), ve bir rakamdan oluşuyor.(detaylar ileride ) . Ve biraz önceki versiyon çakışmaları sorunu da tarih oluyor: çünkü .NET framework aynı isimli assembly’nin değişik versiyonların çalıştırılmasına izin veriyor!! .NET ile yazdığınız programların config dosyası sayesinde, yazdığınız programın public bir assembly’nin hangi versiyonu ile çalışmasını istediğinizi belirtebiliyorsunuz . Yani bu makinada kurulu a.dll’in 2.14 versiyonunu yükle şeklinde ayarlar mümkün . Bu config dosyaları XML standardını kullanıyor.( bunları da detaylı olarak göreceğiz )  

Şimdi isterseniz, bu aşamaya kadar teori ile giden yazılarımızı artık pratiğe dökelim ve ilk assembly’mizi oluşturalım!

Her ne kadar burada anlatacağım  işlemleri visual studio.NET ile yapmak daha kolay olsa da, ben hem herkesin faydalanabilmesi, hem de işin temellerini daha rahat kavramak açısından, sadece .NET framework ile çalışabilecek bir örnek vereceğim. .NET üzerinde en sevdiğim dil olduğu için C# ile yazdığım örnekler kullanacağım, ancak kolayca anlaşılacağına eminim. 

İlk olarak  assembly için kullanılacak olan sınıfları içeren bir dosya oluşturacağız. Dosyamızın adı sharethem.cs olsun. Notepad de dahil olmak üzere basit bir metin editörü yeterli. 

//sharethem.cs 

using System; 

namespace sharedones 

{

       public class container

       {

             public int member1;

             public string member2;

             public container()

             {

             this.member1=10;

             this.member2="Ben bir public elemanim!";

             }

       }

 

//sharethem.cs bitti 

Ben  bu dosyayı save ettikten sonra, kendi sistemimde  

>csc /t:library /out:f:sharethem.dll  f:sharethem.cs 

komutu ile bir dll oluşturdum. Burada önemli bir nokta environment variables ile csc.exe’nin tanımlanmış olması, yoksa c# compiler’ı da tam dizinini girerek çağırmam gerekirdi. 

Şimdi oluşturduğumuz bu dll, başlı başına bir assembly’dir! Daha detaylı olarak belirtirsek, bir private assembly’dir.Şimdi bu assembly içinde paylaşılan container class’ını kullanan bir uygulama yazalım:

NOT:Bu ufak notu, bu makaleyi okuyan arkadaşların uyarısı üzerine ekledim: C# küçük büyük harf ayrımına duyarlı bir dildir. Yani aldığınız herhangi bir hatada, lütfen önce kodunuzu kontrol edin. Eğer bu yazı dizisindeki kodları copy paste ile sorunsuz çalıştırabiliyorsanız, sisteminizde bir sorun olmaması gerekiyor.  

//clientapp.cs 

using System;

using sharedones; 

namespace clientapp

{

            public class clientclass

            {

            public container mycontainer;

            public clientclass()

                        {

                        this.mycontainer=new container();

                        }

            }

 

            public class mainone

            {

            public static void Main()

            {

            clientclass myclient=new clientclass();

            Console.WriteLine(myclient.mycontainer.member2);

            }

            }

}

//clientapp.cs bitti 

Şimdi bu uygulamanın kaynak kodunu derleyelim. Dikkatinizi çektiyse bu kodun içinde

using sharedones;

şeklinde bir satır ile sharedones namespace’ini  kullanacağımızı belirttik, ve daha sonra da bu namespace içindeki container sınıfından faydalandık, burada konuyu fazla dağıtmak istemediğim için C# kodunun detaylı açıklamasına girmek istemiyorum. Bu programı çalıştırdığımız zaman command promt ekranında,

Ben bir public elemanim!

Mesajını göreceğiz. Peki ama biz yazdığımız bu exe’yi bu dll’den nasıl haberdar ettik ? Clientapp.exe yi derlemek için kullandığımız komut satırı bu sorumuzu yanıtlayabilir : 

C:>csc  /r:f:sharethem.dll  /out:f:clientapp.exe  f:clientapp.cs 

Burada  /r:f:sharethem.dll  parametresi bu exe içinde sharethem.dll içinde bulunan herhangi bir kaynağı kullanabileceğimizi belirtiyoruz. (bu arada f: kısmı benim dll’imin path’ini belirtmek için var, yoksa /r: parametresi ile bir ilgisi yok:) 

Peki, buraya kadar sorun yok gibi görünüyor. O zaman bir iki not düşelim ve aklınıza gelebilecek birkaç soruyu yanıtlayalım:

Bu örnekte oluşturduğumuz dll’i  C#’dan başka bir dil ile kullanabilir miyiz ? Kesinlikle evet! Assembly kavramı .NET ‘e ait bir kavram, ve .NET ile uyumlu her dilden assembly’lere erişebiliriz. Yani Visual.basic .NET içerisinden bu assembly içindeki class’a ulaşabilir, ve bu class’ı kullanarak bir nesne oluşturabilirdik. Hatta bu class’dan inherit eden bir başka class bile yazabilirdik! Burada bahsettiğimiz olanaklar klasik com ile mümkün olmayan şeyler. Bu örneklerin, .NET ile gelen kod paylaşımı ve yeniden kod kullanımının ne derecede gelişmiş olduğunu açıklayabildiğini umuyorum..

Şimdi gelelim private ve public assembly konularına. Biraz önce derlediğimiz dll ile bir private assembly oluşturduk, bu private assembly, sadece kendisinden derlenme sırasında haberdar edilen uygulamalar tarafından kullanılır. Clientapp.exe yi derlerken /r: switch’i ile bu işlemi gerçekleştirdik.

Yani yazdığımız programa, çalışırken ihtiyaç duyacağın bazı kaynakları, bu dll içinde bulacaksın dedik. Private olarak hazırlanan assembly’ler kendilerini kullanacak olan uygulamanın bulunduğu dizinde, veya o dizinin alt dizinlerinden birinde bulunmalıdır.Ufak bir deneme yapalım, ve hazırladığımız dll’i exe’nin bulunduğu directory dışında bir yere alıp sonra da exe’yi çalıştıralım, ve bakalım ne olacak : 

C:>F:clientapp.exe 

Unhandled Exception: System.IO.FileNotFoundException: File or assembly name shar

ethem, or one of its dependencies, was not found.

File name: "sharethem"

   at clientapp.mainone.Main() 

Fusion log follows:

LOG: Post policy reference: sharethem, Version=0.0.0.0, Culture=neutral, PublicK

eyToken=null

LOG: Attempting download of new URL file:///F:/sharethem.DLL.

LOG: Attempting download of new URL file:///F:/sharethem/sharethem.DLL.

LOG: Attempting download of new URL file:///F:/sharethem.EXE.

LOG: Attempting download of new URL file:///F:/sharethem/sharethem.EXE. 

Oops, programımız çakıldı!! Nedenini tahmin etmek zor değil, hata mesajından da açıkça anlaşılacağı gibi, aranan kaynaklara ulaşılamadı. Log: satırlarına bakarsanız, .NET runtime’ın

 bu kaynağı mevcut olasılıklar ile aradığını görebilirsiniz. Bu arama işlemine “probing” deniyor.Bu da klasik COM’a göre oldukça yeni bir işleyiş. COM ile çalışırken bu arama işlemi yerine, registy’de kayıtlı bilgiler ile çalışmanız gerekirdi. 

Private assembly’leri tanımlamak için string türünden bir isim ve bir versiyon numarası kullanılır, ancak biraz önce bahsettiğimiz istediğimiz versiyonu yükleme işlemi bu tür assembly’ler için kullanılmaz. Nedeni de açık: sadece tek bir uygulamanın faydalanması için yaratıldığından versiyon değişiklikleri sebebiyle, başka bir uygulamanın çakılması olasılığı yoktur.

Şimdi biraz da Private assembly’ler ve XML konfigurasyon dosyalarına bakalım. Bir .NET uygulaması bir assembly içindeki kaynağı kullanmak isterse, runtime, o uygulamaya ait bir XML konfigürasyon dosyası arar.Bu dosyalar XML syntax’ı ile yazılmış olmalıdır, ve aynı zamanda .config uzantısı taşımaları ve ait oldukları uygulama ile aynı isimde olmaları gerekir.Bu noktayı biraz açarsak: clientapp.exe için kullanacağımız dosya: clientapp.exe.config şeklinde olmalıdır.

Gerçek hayatta private assembly’ler kullanan bir uygulama yazdığınız zaman, muhtemelen bu uygulamanızdaki kaynakları düzenli bir şekilde yerleştirmek isteyeceksiniz. Yani dll’leri ayrı bir dizin içinde, resimleri ve sesleri ayrı bir dizinde bulundurmak isteyeceksiniz.Bu durumda oluşturduğunuz bu yapıyı XML dosyanızda belirterek, programınıza hangi kaynağı nerede arayacağını söyleyebilirsiniz.Hemen bir örnekle bu işi nasıl yapacağımızı görelim:

Daha önce yarattığımız küçük  örnek uygulamamız olan clientapp ‘ın bulunduğu dizinde bir klasör oluşturalım ve adına da dll diyelim.Sonra da sharethem.dll’i bu klasöre taşıyalım.

Şimdi notepad ile aşağıdaki dosyayı oluşturup, sonra da Clientapp.exe.config olarak exe’nin bulunduğu yere kayıt edelim.     

Yukarıdaki dosyayı kaydettikten sonra, programımız sorunsuz bir şekilde çalışacaktır.Şimdi dilerseniz, bu dosya ile gerçekleştirdiğimiz işleme, ve bir programın çalışırken private assembly’leri kullanma mekanizmasına yakından bakalım.  

İlk olarak bu işlemin adını verelim : “binding” Yani bağlanma olarak çevirebiliriz.Aslında mantıklı bir terim, çünkü programınız bir assemmbly’e bağlanıyor, ve ihtiyaç duyduğu kaynakları kullanıyor.

Binding işlemi iki türlü gerçekleşebilir, explicit, veya implicit, yani sizin yazdığınız bir kodla özel olarak istediğiniz assembly’e erişilebilir, veya siz bir assembly içindeki bir kaynağa referans verdiğiniz zaman bu kaynağa runtime tarafından otomatik olarak erişilir.

Mesela biraz önce gördüğümüz gibi kodunuzu derlerken /r: anahtarı ile bir dll i çağırarak, otomatik olarak o assembly’e bağlanılmasını sağlamış olursunuz.

Compile ederken değil de programınızın içinden istediğiniz bir assembly’e erişmek için :

Assembly benim_assembly= Assembly.Load(“ShareThem, ver=1.2.0990”);

Gibi bir C# örneğini verebiliriz. 

Binding işlemi ile ilgili bilmemiz gereken bir başka terim de “Application Directory”, yani uygulama dizini. Karışık bir kavram değil, aksine son derece basit: .NET programınızın ve onun kullandığı (eğer varsa ) diğer dizinlerin içinde bulunduğu ana dizin.  

Binding nasıl oluyor ?

Binding işlemi, yani bir asssembly’e erişme işlemi için izlenen adımlara bakalım. Otomatik olarak veya kod ile manuel olarak bir binding işlemi istenince, runtime Assembly resolver denilen mekanizmaya  AssembylRef dediğimiz bilgiler topluluğunu yollar. Yani siz programınızda herhangi bir assembly’i kullanmak istediğinizde, .NET runtime, bu assembly’e ilişkin bilgileri toplar ( adı , versiyon numarası ve bir iki diğer özellik ) ve gidip assembly resolver denilen mekanizmaya, “Bu program, elimdeki bu bilgilere uyan bir assembly arıyor, acaba bunu bulabilir misin ?” der. 

Bu aşamada top assembly resolver’a geçtiği için Assembly Resolver önce bu arananın public mi yoksa private bir assembly mi olduğunu kontrol eder ( farkları ileride göreceğiz ) . Eğer private ise (ki biz şu anda bu konuyu incelediğimiz için öyle olduğunu farzediyoruz ) adım adım şu işlemler yapılır: 

İlk aşamada bir konfigürasyon dosyası aranır. Bu dosya içinde biraz önce belirttiğimiz gibi gerekli bazı bilgiler ve arama işlemine dahil edilecek bazı dizinler bulunur.

Eğer bu dosya bulunamazsa, uygulamanın bulunduğu ana dizin ( application directory ) aranır, eğer dosya varsa , orada belirtilen alt dizinlerde de istenilen assembly için arama yapılır. Biraz yukarıdaki örnekte kullanmak istediğimiz dll’i silince neler olduğunu, ve özellikle aldığımız hata mesajını hatırlayın. Şimdi o mesaj size daha anlamlı geliyordur sanıyorum.

En son olarak da bu aramalardan sonuç alınamazsa, bizim tecrübe ettiğimiz hata ortaya çıkar, ve TypeLoadException fırlatılır. ( Exception nedir diyorsanız: bu da başka bir yazıda incelenecek bir konu :)

Oldukça yoğun bilgi içeren bir yazı oldu, ama private assembly’ler için bu aşamada yeterli bilgiyi verdiğimize inanıyorum. Şimdi bu kısmı  kapattığımıza göre sıra public assembly’ler ve glabal olarak bir kaynağı nasıl paylaşacağımıza geldi. Bu kısımda edindiğimiz temel bilgiler yardımıyla, oldukça detaylı bir şekilde shared , yani public assembly’leri de işleyeceğiz. Bir sonraki yazıya kadar, bu alandaki bilgilerinizi kafanızda sağlam bir şekilde oturtmanızı tavsiye ederim. Aklınıza gelen sorular için forum’u kullanabilirsiniz. Bizi biraz daha zorlu birkaç kavram bekliyor, ancak bu temel kavramları ve bilgileri edindikten sonra .NET üzerinde çok daha sağlam bir hakimiyetiniz olduğunu göreceksiniz. Tekrar görüşmek üzere.

Şeref Arıkan

Döküman Arama

Başlık :

Kapat