Daha önce hazırladığım Dependency Injection Tasarım Deseni başlıklı yazıda, yazılım tasarımında sınıfların birbirine olan bağımlılıklarını esnetmeyi ve bağımlılıkların sınıf dışından enjekte edilmesini incelemiştik. Bu yazımızda ise konunun bir örnek uygulaması niteliğinde olan ASP.NET MVC uygulamalarında Dependency Injection uygulamasını inceleyeceğiz.
Bu yazımızdaki örnek uygulamamızı geliştirirken, soyut sınıflar ile somut sınıflar arasındaki bağlantıyı kurarken ve somut nesne oluştururken IoC Container denen yardımcı kütüphanelerden faydalanacağız. Yine bu örnek uygulamada IoC Container kütüphanesi ile somut nesnelerin kullanıcı(client) sınıf içerisinde “new” anahtar sözcüğü ile oluşturmak yerine, IoC Container tarafından oluşturulduğunu göreceğiz.
Örnek Uygulama
Örnek uygulamamızda ASP.NET MVC controller sınıfına Dependency Injection tarasım deseni ile bağımlılıkları dışarıdan soyut nesneler(interface veya abstract) yardımıyla vererek uygulamayı çalıştırmayı deneyeceğiz.
Öncelikle Controller sınıfımızı tanımlayarak işe başlayabiliriz.
public class HomeController : Controller { private readonly IProductService productService; public HomeController(IProductService productService) { this.productService = productService; } public JsonResult Index() { IEnumerable<Product> products = productService.GetBestSellers(); return Json(products, JsonRequestBehavior.AllowGet); } }
Gördüğünüz üzere, Controller sınıfında hiç bir şekilde nesne oluşturma işlemi gerçekleştirilmiyor. Dışarıda oluşturulan ProductService nesneleri Controller sınıfı içerisine enjekte ediliyor. IProductService tipi bir interface’dir. Bu interface tipini uygulayan sınıflar HomeController içerisinde çalışabilir. IProductController tipindeki nesneler constructor metodu yardımıyla sınıf içerisine alınıyor.
ASP.NET MVC Controller sınıflarının varsayılan(default) halleri çalışma zamanında parametresiz constructor metodlarını ararlar. Bu tanımlama ASP.NET DefaultControllerFactory içerisinde belirlenmiştir. ASP.NET MVC open source olduğundan isteyen MVC kodlarını açıp inceleyebilir. Biz constructor seviyesinde injection işlemi yapacağımızdan DefaultControllerFactory sınıfının GetControllerInstence metodunu ezerek yani yeniden tanımlayarak istediğimiz formata getirmeliyiz.
Bu tanımlamayı yapmadan önce uygulamada kullanacağımız NInject kütüphanesinden bir iki cümle ile bahsedelim. Ninject kitüphanesi bir konteynır olarak çalışır. Soyut nesneler ile somut nesnelerin eşleştirildiği ve istendiğinde somut nesnelerin(new) oluşturulduğu kütüphanelerdir.
public class NinjectControllerFactory : DefaultControllerFactory { private readonly IKernel kernel; public NinjectControllerFactory() { kernel = new StandardKernel(new NinjectBindingModule()); } protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { return controllerType == null ? null : (IController)kernel.Get(controllerType); } } public class NinjectBindingModule : NinjectModule { public override void Load() { Kernel.Bind<IProductService>().To<ProductService>(); } }
Burada tanımlanan kod parçasında anlatılmak istenen şey DefaultControllerFactory metodunun Controller Instance oluştururken karşılaşacağı parametresiz constructor metodu oluşturma hatasını engellemektir. Ninject aracılığı ile Controller tipine göre bir nesne oluşturuyor. Örneğin HomeController için controllerType HomeController olacaktır ve constructor metodunda IProductService interface tipini parametre olarak alacaktır. HomeController tipinde bir nesne oluştururken constructor metodda karşılaştığı parametreyi Kernel bildiği için hemen nesnesini oluşturarak Controller sınıfına vermektedir.
Artık Global.asax sınıfı içerisine bu yapıyı tanıtma işlemi kaldı. Onu da şu şeklide gerçekleştirebiliriz.
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { //diğer tanımlamalar... ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory()); } }
Uygulamayı çalıştırdığımızda çıktı olarak şu şekilde bir JSON veri dönecek:
[{"Name":"Notebook"},{"Name":"PC"}]
Örnek uygulamanın kodlarını SkyDrive üzerinden paylaştım. Bir sonraki yazıda görüşmek üzere.
Kaynak Kodlar: Burada