Dependency Injection – Ninject’e Giriş

   Bir önceki yazımla giriş yaptığımız Dependency Injection kavramı ardından sıra geldi Dependency Injection kütüphaneleri incelemeye. Önceliği gerek kullanımın kolay olması, gerekse de görece güncel olması nedeniyle pek çok yeni C# özelliğini kullandıran Ninject’e veriyorum.

   Hatırlayacak olursak, bir önceki yazımda bağımlılıkları dışarıdan enjekte edilmek üzere OgrenciIslemleri sınıfımızı aşağıdaki şekilde hazırlamıştık;

internal class OgrenciIslemleri {
    private readonly IVeriDeposu veriDeposu;
	private readonly IGunlukDeposu gunlukDeposu;
	
	public OgrenciIslemleri(IVeriDeposu veriDeposu, IGunlukDeposu gunlukDeposu) {
		this.veriDeposu = veriDeposu;
		this.gunlukDeposu = gunlukDeposu;
	}

	public void OgrenciKaydet(Ogrenci ogrenci) {
		try {
			gunlukDeposu.Debug("Öğrenci kaydı yapılıyor...");
			
			var referansId = veriDeposu.Kaydet(ogrenci);
			
			gunlukDeposu.Debug("Öğrenci kaydı yapıldı. Referans Id : {0}", referansId);
		}
        catch (Exception istisna){
			gunlukDeposu.Error("Öğrenci kaydı sırasında beklenmeyen bir hata oluştu : {0}", istisna);
		}
	}
}

   Devamında da uygulamamızın ana fonksiyonu içerisinde bağımlıklıkları aşağıdaki şekilde enjekte etmiştik;

class Program {
    static void Main(string[] args) {
        var ogrenci = new Ogrenci {
            No = 12345,
            Adi = "Fatih",
            Soyadi = "Boy",
            Bolum = "Bilgisayar Mühendisliği"
        };
 
        IVeriDeposu veriDeposu = new VeriTabaniDesposu();
        IGunlukDeposu gunlukDeposu = new TextGunlukDeposu();
        
        var ogrenciIslemleri = new OgrenciIslemleri(veriDeposu, gunlukDeposu);
 
        ogrenciIslemleri.OgrenciKaydet(ogrenci);
    }
}

   Ninject’in kullanımı da aslında bu kadar kolay. Öncelikle projemize Ninject NuGet paketini eklemeliyiz;

Ninject NuGet paketi

   Devamında da tüm sihirin döneceği Ninject çekirdeğini ilklendirmeliyiz;

IKernel kernel = new StandardKernel();

   Bir sonraki adımda Ninject çekirdeğine, arayüzler ve implementasyonları eşleştirmelerini bildirmeliyiz;

kernel.Bind<IVeriDeposu>().To<XmlDosyaVeriDesposu>();
kernel.Bind<IGunlukDeposu>().To<TextGunlukDeposu>();

   Her ne kadar yukarıdaki satırlarda Ninject söz dizimi neler olup dittiğini anlatıyor olsa da bir kez de ben belirtmek isterim. Ninject çekirdeğine IVeriDeposu arayüzü sorulduğunda yanıt olarak XmlDosyaVeriDesposu sınıfının bir örneğini vermesi gerektiğini, IGunlukDeposu sorulduğunda ise TextGunlukDeposu sınıfının bir örneğini vermesi gerektiğini ifade ediyoruz.

   Son adımda ise Ninject çekirdeğinden OgrenciIslemleri sınıfının bir örneğini istiyoruz;

var ogrenciIslemleri = kernel.Get<OgrenciIslemleri>();

   Kodumuzu toplarladığımızda aşağıdaki şekilde olacaktır;

class Program {
    static void Main(string[] args) {
        var ogrenci = new Ogrenci {
            No = 12345,
            Adi = "Fatih",
            Soyadi = "Boy",
            Bolum = "Bilgisayar Mühendisliği"
        };

        IKernel kernel = new StandardKernel();

        kernel.Bind<IVeriDeposu>().To<XmlDosyaVeriDesposu>();
        kernel.Bind<IGunlukDeposu>().To<TextGunlukDeposu>();

        var ogrenciIslemleri = kernel.Get<OgrenciIslemleri>();

        ogrenciIslemleri.OgrenciKaydet(ogrenci);
    }
}

   Bu kadar basit..

   Şimdi sıra geldi arka planda olup biteni incelemeye;

  Tür eşleştirmeleri ile birlikte Ninject çekirdeğine neleri kullanmak istediğimizi belirttik; ama dikkat edecek olursanız bu tanımlamalar arasında OgrenciIslemleri için bir girdi bulunmuyor. Ninject, tanımlaması yapılmamış türler için akıllı bir strateji takip etmekte. Buna göre, eğer talep edilen tür için bir tanım bulunmuyorsa; fakat bu türün bir örneğini oluşturabiliyorsa (yani interface, abstract sınıf v.s. değilse) varsayılan bir tanım ekleyerek türü yine kendisiyle eşleştirir.

   Sonraki adımda sıra geliyor OgrenciIslemleri sınıfını ilklendirmeye. Ninject, öncelikle sınıfın varsayılan constructer’ı olup olmadığını kontrol edecektir. Bizim örneğimizde olduğu gibi varsayılan constructer’ın bulunmaması durumunda ise bulduğu constructer’lar arasında en fazla tür bilgisi eşleştirmesine sahip olduğu constructer’ı kullanacaktır. IVeriDeposu’nun bir örneğinin talep edildiği ilk parametre için Ninject XmlDosyaVeriDeposu’nu kullanırken, IGunlukDeposu örneği olarak TextGunlukDeposu kullanılacaktır. Bu iki parametre ile OgrenciIslemleri sınıfı ilklendirilerek bize teslim edilecektir.

   Ninject’in en sevdiğim özelliklerinden birisi de yukarıda sıraladığım ilklendirme silsilesini bağlı tüm türler için iç içer yapabilmesi. Örneğin; IVeriDeposu örneği için tanımladığımız XmlDosyaVeriDesposu sınıfıda constructer’ında aşağıdaki gibi IGunlukDeposu örneği talep etseydi kodumuzda en ufak bir değişiklik yapmamıza gerek olmayacaktı.

internal class XmlDosyaVeriDesposu : IVeriDeposu {
    private readonly IGunlukDeposu gunlukDeposu;
    
    public XmlDosyaVeriDesposu(IGunlukDeposu gunlukDeposu){
		this.gunlukDeposu = gunlukDeposu;
    }
    
    public long Kaydet(object veri) {
        throw new NotImplementedException();
    }
}

   Örnekten de görebileceğiniz gibi, Ninject’in yukarıda paylaştığım ilklendirme mekanizması sayesinde uygulamamız içerisinde oldukça esnekliğe sahip olabiliriz. Uygulama bileşenlerimiz doğrudan birbirleri hakkında bilgi sahibi olmayarak tüm iletişim arayüzler (kontratlarımız) üzerinden gideceği için istediğimiz anda, istediğimiz bileşeni bir başka implementasyonu ile değiştirmemiz oldukça kolay. Aslında bu bahsettiğim durum önceki makalemde sözünü ettiğim gevşek bağlı (loosely coupled) uygulama prensibine bire bir uymakta.

   Enjeksiyon desenleri;

    Dikkat ettiyseniz şimdiye kadar paylaştığım örnekler Constructer Injection yöntemini kullanmakta. Ninject, Constructer Injection dışında Property Setter Injection ve Setter Method Injection yöntemlerini de desteklemekte.

   Property Setter Injection yönetimde, Ninject’in bağımlılıkları enjekte etmesini istediğiniz property’leri belirtmeniz gereklidir. Bu ön koşul isteminiz dışında tüm property’lere enjeksiyon yapılmasının önüne geçtiği gibi performansa da olumlu bir etkisi vardı. Property’lerin işaretlenmesi işi Inject özniteliği yardımıyla aşağıdaki şekilde yapılabilir;

internal class OgrenciIslemleri {
	[Inject]
    public IVeriDeposu VeriDeposu { private get; set; }
	
	[Inject]
	public IGunlukDeposu GunlukDeposu { private get; set; }

	public void OgrenciKaydet(Ogrenci ogrenci) {
		try {
			GunlukDeposu.Debug("Öğrenci kaydı yapılıyor...");
			
			var referansId = VeriDeposu.Kaydet(ogrenci);
			
			GunlukDeposu.Debug("Öğrenci kaydı yapıldı. Referans Id : {0}", referansId);
		}
        catch (Exception istisna){
			GunlukDeposu.Error("Öğrenci kaydı sırasında beklenmeyen bir hata oluştu : {0}", istisna);
		}
	}
}

   Ninject bu örnekte VeriDeposu ve GunlukDeposu property’lerini işaretlediğimiz için OgrenciIslemleri sınıfını ilklendirdikten sonra enjekte edecektir.

   Benzer şekilde, OgrenciIslemleri sınıfına Setter Method Injection yöntemi ile bağımlılıkları enjekte edebiliriz;

internal class OgrenciIslemleri {
    private IVeriDeposu veriDeposu;
	private IGunlukDeposu gunlukDeposu;
	
	[Inject]
    public void VeriDeposu(IVeriDeposu veriDeposu){
        this.veriDeposu = veriDeposu;
    }
	
	
	[Inject]
    public void GunlukDeposu(IGunlukDeposu gunlukDeposu){
        this.gunlukDeposu = gunlukDeposu;
    }

	public void OgrenciKaydet(Ogrenci ogrenci) {
		try {
			gunlukDeposu.Debug("Öğrenci kaydı yapılıyor...");
			
			var referansId = veriDeposu.Kaydet(ogrenci);
			
			gunlukDeposu.Debug("Öğrenci kaydı yapıldı. Referans Id : {0}", referansId);
		}
        catch (Exception istisna){
			gunlukDeposu.Error("Öğrenci kaydı sırasında beklenmeyen bir hata oluştu : {0}", istisna);
		}
	}
}

   İlerleyen makalelerde, paylaşacağım örneklerle Ninject (dolayısıyla da Dependency Injection) ile birlikte elde ettiğimiz bu gevşek bağların uygulama tasarımımızı nasıl olumlu yönde etkilediğini göreceğiz.

Fatih Boy

Ankara'da yaşayan Fatih, bir kamu kurumunda danışman olarak çalışmaktadır. ALM süreçleri, kurumsal veri yolu sistemleri, kurumsal altyapı ve yazılım geliştirme konularında destek vermektedir. Boş zamanlarında açık kaynak kodlu projeler geliştirmeyi ve bilgisini yazdığı makalelerle paylaşmayı seven Fatih, aynı zamanda Visual C# ve Visual Studio teknolojileri konusundan Microsoft tarafından altı yıl üst üste MVP (En Değerli Profesyonel) ödülüne layık görülmüştür. İş hayatı boyunca masaüstü uygulamaları, web teknolojileri, akıllı istemciler gibi konularda Asp.Net, Php, C#, Java programlama dilleri ve MySql, MsSql ve Oracle gibi veritabanı yönetim yazılımları ile çalışmıştır. İngilizce ve Türkçe olarak yayınlanan makalelerini gerek İngilizce bloğunda, gerekse de Türkçe bloğunda bulabileceğiniz gibi web sitesinden de açık kaynak kodlu geliştirdiği yazılımlarına ulaşabilirsiniz. vCard - Twitter - Facebook - Google+

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir