Makale Özeti

Side By Side Execution (Yan Yana Çalışma) Side By Side Execution aynı isimli birden fazla uygulamanın yan yana , paralel olarak çalışabilmeleridir...

Makale

Side By Side Execution (Yan Yana Çalışma)

Side By Side Execution aynı isimli birden fazla uygulamanın yan yana , paralel olarak çalışabilmeleridir.

Side by Side Execution kavramı içersinde iki çeşit yan yana çalışmadan bahsedebiliriz.

  1. Aynı dll in farklı versiyonlarının yan yana çalıştırılması
  2. Birden fazla .Net Framework ün aynı makinada yan yana çalışması

Biz bu yazımızda aynı dll in farklı versiyonlarının yan yana çalıştırılmasını inceleyeceğiz.Ancak detaylara girmeden önce niçin böyle bir şeye ihtiyaç olduğunu anlamaya çalışalım.

Com teknolojisi ile yazılmış olan dll leri kullanabilmek için , bu uygulamaları Register etmek ,Yani Windows un registry sine eklemek ve. Registry ye de, Dll ile ilgili bir takım bilgilerin yazılması gerekirdi .Örneğin bir Class ID (Sınıf Numarası) , Dll in bulunduğu dizin vb. Yazdığımız uygulamalarda ise, herhangi bir Com dll ini kullabilmek için o dll in registry de kayıtlı Class id sini kullanırız. Bu class id registry den bulunur ,dll in  dizinine ulaşılır ve oradan uygulamaya eklenir.Bu şekilde birden fazla uygulamanın aynı dll i kullanabilmeleri sağlanır.

Birden fazla uygulamanın kullandığı bir Com dll ini kullanırken ,bir uygulamanın yeni versiyonunun bu dll i  değiştirdiğini düşünelim. Yazılan bu yeni dll ile yeni versiyon uygulama sorunsuz olarak çalışacaktır. Peki aynı dll i kullanan diğer uygulamalara ne olur? Diğer uygulamalar kullandıları dll değiştiği için çalışmayacaktır. Aynı Com dll ini kullanan uygulamaların , dll in değişmesi sonucunda çalışmaz hale gelmesine Dll Hell (Dll Cehennemi) denir.

Ayrıca , daha önce den yazılmış bir Com dll i üzerinde değişiklik yapmak istediğimizde , değişikliği yaptıktan sonra  dll i derlerken bir önceki dll e uygun şekilde(compatible) derlenmesi gerekir. Aksi takdirde yazdığımız Dll , onu kullanan uygulamalar tarafından çağırılamayacaktır.

İşte yukarıda açıkladığımız durumlardan dolayı Com teknolojisi getirdiği tüm yeniliklerin yanında bu konuda iki büyük sorunu içerir. Şimdi bu sorunların .Net ile birlikte nasıl çözülebildiğine bakalım.

Assembly Kavramı

Artık hepimiz biliyoruz ki .Net ile yazılan uygulamalar derlenirlerken MSIL denen ortak bir dile çevrilirler.Bu şekilde yaratılan , her yeni .Net uygulaması birer Assembly olarak adlandırılırlar. Assembly kavramını derin bir şekilde burada incelemeyeceğim ancak şunu belirtmekte fayda var, Assembly lerin en büyük özelliği üzerlerinde taşıdıkları Metadata dır. Metadata nın  içinde yazdığımız .Net uygulamasına ait versiyon, açıklama veya uygulamanın yazarı, gibi bir takım bilgiler bulunur.

Yaratılan her assembly aynı zamanda taşınabilir bir uygulama olarak adlandırılır. (Portable Executable PE). Bu uygulamalar ilk çalıştırıldıklarında JIT compiler lar tarafından çalıştırılacakları makinaya uygun şekilde compile edilirler ve makina koduna çevrilirler.

.Net te iki, adet Assembly kavramı vardır.

  • Özel Assembly (Private Assembly)
  • Genel Assembly (Public Assembly)

Özel Assembly ler sadece bir uygulama tarafından kullanılırlar ve o uygulamanın çalıştığı dizinle aynı dizinde bulunmalıdırlar.

Genel Assembly ler ise GAC (Global Assembly Cache) ta bulunurlar ve birden fazla uygulama tarafından kullanılabilirler. GAC ın en büyük özelliği, aynı uygulamalanın birden fazla versiyonunun,  versiyon numaraları bazında tutulmasıdır.

İşte  bu durum Com teknolojisini doğurduğu Dll Hell kavramının çözümüdür. Yani GAC ta duran bir uygulamayı versiyon numarasanına bağlı olarak kullanabiliriz. Bir uygulama bir dll in 1.0 versiyonunu kullanırken , bir diğer uygulama ayni dll in 2.0 versiyonun kullanabilmektedir. Bu duruma Yan Yana Çalışma (Side by Side Execution) denir.

Peki yazdığımız bir dll i GAC a nasıl koyacağız. Öncelikle herhangi bir assembly i GAC a koyabilmek o assembly için bir Strong Name yaratmamız gerekir.

Strong Name Nedir?

Bir uygulamayı paylaşılabilen bir uygulama yapmak , dolayısı ile  GAC a koyabilmek için , o uygulamayı derlemeden önce bir genel anahtar (public key) ve bir dijital imzadan (digital signature) oluşan bir anahtar takımı (key pair) yaratmamız gerekir. İşte bu anahtar takımına Strong Name denir.

Bir assembly e bir Strong Name atanması sırasında , assembly ye dijital bir anahtar atanır. Yaratılan anahtarın bir kısmı , assembly nin içeriğinin bir hash kodundan oluşur ve bu dijital anahtar assembly nin içerisine eklenir.

CLR (Comman Language Runtime) , assembly yi yüklerken,  içeriğinin  hash değerini hesaplar  ve içide gelen  hash değeri ile karşılaştırırak assembly nin değiştirilip değiştirilmediğini kontrol eder. Bu şekilde assembly nin içeriğinin değiştirilmediğinden emin olarak kullanır.

Peki Strong Name i nasıl yaratacağız?

Bunun için .Net içerisinde gelen sn.exe programını kullanacağız.

Visual Studio Command Prompt u açıp, sn -k c:\yazgelistir.snk  yazalım. Bu ifade ile c:\ dizininde yazgelistir.snk isimli, içinde bir anahtar bulunduran bir dosya oluşacaktır.

Yarattığımız bu dosyayı assembly içerisine nasıl ekleyebileceğimizi örnek bir kod üzerinde inceleyelim. Örnek kodumuz sonunda bir dll oluşturacağız..

using System;
using System.Reflection;
using System.Runtime.CompilerServices;

[assembly: AssemblyVersion("1.0.0.1")]
[assembly: AssemblyKeyFile("yazgelistir.snk")]
namespace YazGelistir
{
    public class YazGelistir
    {
        public YazGelistir()
        {
        }
        public void WriteVer()
        {
            Console.WriteLine("YazGelistir.dll ver:1.0.0.1");
        }
    }
}

Örnek kodumuzda , dikkatinizi çekecek , namespace ifadesinin üzerinde iki satır var.

[assembly: AssemblyVersion("1.0.0.1")] satırında yazdığımız assembly nin versiyon numarasını veriyoruz. Bu ilk dll imiz olduğu için versiyon numarası 1.0.0.1.

[assembly: AssemblyKeyFile("yazgelistir.snk")] satırında ise yazdığımız assembly i derlerken , kullanacağımız strong name anahtarının içinde bulunduğu dosyanın ismini veriyoruz.

Örnek kodumuz da c: dizininde olduğu için anahtar barındıran dosyanın dizinini yazmadık. Eğer anahtar içeren dosyalar için başka bir dizin kullanıyorsak, örneğin  dosyayı c:\keys dizini altında yarattıysak , anahtar içeren dosyanın yerini [assembly: AssemblyKeyFile(@"c:\Keys\yazgelistir.snk")] şeklinde de belirtebiliriz.

Assembly lere ait metadata bilgileri , Visual Studio.Net içerisinden yaratılan projelerde , proje içerisine otomatik olarak eklenen AssemblyInfo.cs dosyası içerisinde bulunurlar. Örnek kodumuzu Notepad ile yazdığımdan , oluşacak assembly ile ilgili bilgileri direk olarak koda ekledim. AssemblyInfo.cs dosyasında yukarıda belirttiğimiz ifadeleri aynen bulabileceğiniz gibi, bu ifadeler dışında Assembly nin farklı özelliklerini de girebilirsiniz.

Şimdi örnek kodumuzu derleyelim.

Visual Studio Command Prompt u açıp csc /target:library /out:yazgelistir.dll yazgelistir.cs komut satırı ile  kodumuzu derleyelim.Örnek kodumuzun bulunduğu dizinde yazgelistir.dll adında bir dosya oluştuğunu göreceğiz.

Gelelim bu dll i nasıl GAC a atacağımıza? Bunun içinde .Net içerisinde gelen gacutil.exe isimli komut satırı programını kullanacağız.

Visual Studio Command Prompt u açıp  gacutil /i yazgelistir.dll komut satırını ile dll imizi GAC a atabiliriz. Komut satırını çalıştırdıktan sonra ekrana gelen "Assembly successfully added to cache" ifadesi bize dll imizin doğru olarak GAC a atıldığını gösterir. Ayrıca c:\Windows\Assembly dizini altında da Assembly mizi aşağıdaki şekilde görebiliriz.

Gördüğünüz gibi yazgelistir isimli assembly nin 1.0.0.1 versiyonu GAC içerisinde gözüküyor.

GAC taki bir assembly yi , GAC tan çıkarmak için , komut satırında gacutil /u yazgelistir  yazıp çalıştırmamız yeterli olacaktır. Eğer assembly nin birden fazla versiyonu GAC ta duruyorsa ,komut satırında gacutil /u yazgelistir, Version=1.0.0.1 satırını çalıştırarak sadece 1.0.0.1 versiyonlu assembly i GAC tan çıkarmış oluruz.Ayrıca c:\Windows\assembly dizinindeki assembly üzerine sağ tıklayıp Delete adımını seçerek GAC tan seçtiğimiz assembly yi çıkarabiliriz.

Gelelim bu assembly i nasıl kullanacağımıza.

Bunun için aşağıdaki örnek kodumuzu inceleyelim.

using System;

namespace DllTest
{
    class Class1
    {
        [STAThread]
        static void Main(string[] args)
        {
            YazGelistir.YazGelistir yaz=new YazGelistir.YazGelistir();
            yaz.WriteVer();
            Console.ReadLine();
        }
    }
}

Kodumuz içerisinde ,YazGelistir namespace içindeki YazGelistir sınıfından bir nesne yaratıyoruz ve nesnenin içerisindeki WriteVer metodunu kullanarak ekrana YazGelistir.dll in kullandığımız versiyonunun numarasını yazdırıyoruz.

Örnek kodumuzu DllTest.cs isimli bir dosyaya kaydedip bu dosyayı da yazgelistir.dll dosyasının bulunduğu dizine koyuyoruz ,

csc /t:exe /out:DllTest.exe /r:yazgelistir.dll  dlltest.cs komut satırı ile derliyoruz ve DllTest.exe isimli konsol uygulamamızı yaratmış oluyoruz.

DllTest.exe isimli dosyayı çalıştırdığımızda ekranımıza aşağıdaki gibi bir pencere açılır ve içerisinde kullandığımız dll in versiyonu yazar.

Buraya kadar herşey beklediğimiz gibi,  çünkü uygulamamızı yazdığımız yazgelistir dll inin 1.0.0.1 versiyonu ile derledik ekranımıza da dll in versiyonu 1.0.0.1 olarak geldi.

Peki YazGelistir.dll isimli assembly nin bir üst versiyonunu yazıp ve uygulamamızı tekrar derlemeden yeni versiyonun kullanılmaya başlanmasını istiyorsak ne yapacağız? İşte bu durumda .Net in yetenekleri devreye giriyor.

Yeni versiyonumuzun koduna bakalım.

using System;
using System.Reflection;
using System.Runtime.CompilerServices;

[assembly: AssemblyVersion("2.0.0.1")]
[assembly: AssemblyKeyFile("YazGelistir.snk")]
namespace YazGelistir
{
    public class YazGelistir
    {
        public YazGelistir()
        {
        }
        public void WriteVer()
        {
            Console.WriteLine("YazGelistir.dll ver:2.0.0.1");
        }
    }
}

İlk dll deki koddan tek farkı Versiyon numarasının 2.0.0.1 olması. Dll i tekrar derleyip, GAC a attıktan sonra aşağıda da gördüğümüz gibi GAC ta artık iki tane yazgelistir isimli assembly bulunmakta.

GAC ta aynı assembly nin birden fazla versiyonunun olabilmesi Com da yaşadığımız Dll Hell sorununun bu şekilde aşılabileceğini gösteriyor. Dolayısı ile aynı assembly nin farklı versiyonlarını farklı uygulamarda da kullanabiliriz.

DllTest isimli uygulamamızın artık 2.0.0.1 versiyon numaralı yazgelistir dll ini kullanmasını istiyoruz. Bunun için uygulamamızın bulunduğu dizine DllTest.exe.config isimli bir konfigürasyon dosyası ekleyeceğiz ve içinde aşağıdaki satırlar olacak.

Şimdi tekrar DllTest uygulamamızı çalıştıralım.Sonuç aşağıdaki gibi olacaktır.

Uygulamızı tekrar derlemememize rağmen , uygulamamız artık yeni versiyon dll i kullanıyor. Peki bu nasıl oluyor?

CLR tarafından çalıştırılan uygulamalar , bulundukları dizinde kendi isimlerinde konfigürasyon dosyası ararlar.Uygulama konfigürasyon dosyaları, aslında birer Xml dökümanıdır. (Bizim örneğimizde bu konfigürasyon dosyası DllTest.exe.config dosyasıdır.) Uygulama çalıştırılmaya başlandığında konfigürasyon dosyasını bulurlarsa, içinde uygulamanın çalışmasına yönelik bir takım parametrelerin  olabileceğini anlarlar ve bu dosyadaki parametreleri dikkate alarak çalışırlar.

Bizim konfigürasyon dosyamızda , uygulamımızın bir assembly e  bağlı olduğunu belirtiyoruz. ifadesi ile bağlı bulunulan assembly nin GAC taki adını ve genel anahtar bilgisini veriyoruz.

ifadesinde ise 1.0.0.1 versiyonun yerine 2.0.0.1 versiyonunun kullanılması gerektiğini anlatıyoruz.

Uygulama çalışırken artık yazgelistir assembly sinin 2.0.0.1 versiyonunu  GAC tan alıp kullanmaya başlıyor.

Bu şekilde, bir uygulamanın yeni versiyon bir assembly yi , uygulamayı derlemeden kullanabilmesini sağlıyabiliyoruz.Kurumsal ve çok şubeli şirketlerde, çalışan bir uygulamanın kullandığı bir assembly nin farklı versiyonunu, uygulamayı derlemenden sadece bir konfigürasyon dosyası üzerinden yapabilmek , çalışma sürekliliği ve uygulama dağıtımı açısından çok faydalı bir özellik olarak kullanılabilir.

Sonuç

.Net Gac ta bir assembly nin farklı versiyonlarının bulunabilmesi ile Com da yaşadığımız Dll Hell sorununu ortadan kaldırdığı gibi, uygulamaların farklı versiyonları kullanmaya başlamasını sadece bir konfigürasyon dosyasına bağlamış oluyor.

Umarım faydalı bir yazı olmuştur. Sorunlarınızı cemkubilays@hotmail.com e-mail adresine gönderebilirsiniz.