Application Repository Ninject Modülü

29 May

Bu yazımızda, veri merkezli(data centric) uygulamalarda alışılagelmiş bir yöntem olan Repository kullanımının, birden fazla veri kaynağının bulunduğu durumlarda nasıl yapılması gerektiği konusunu incelemeye çalışacağız.

Repository mantığında öncelikle tüm alt sınıfları hiyerarşik bir düzene sokmak adına tanımlanan bir interface vardır. Örnek olarak basit bir interface tanımlamasını şu şekilde ifade ediyor olalım.


public interface IRepository<T>
{
    void Add(T entity);
    IList<T> GetAll();
}

Bu interface altında veritabanına ekleme ve veritabanından veri getirme gibi iki temel işlem vardır. Eğer bir SQL veri tabanına veri yazmayı amaçlıyorsak bu işlemi gerçekleştiren somut sınıfın oluşturulması gerekmektedir.


 public class SqlRepository<T> : IRepository<T>
 {
   public void Add(T entity)
   {
       // Veritabanına ekle..
   }

   public IList<T> GetAll()
   {
       // Veritananından oku..
   }
 }

Buraya kadar işler normal akışında seyrediyor. Ancak SQL veri tabanına yazılamadığı durumlarda ne olacağı bir soru işareti. Ya da başka bir sebepten dolayı ilişkisel veri tabanına yazmak yerine kayıtları XML bir dosyaya yazmak gerektiğinde XML dosya ile çalışabilen somut bir repository oluşturulması gerekmektedir. Bu durumda yeni bir sınıfa ihtiyaç duyulmaktadır.


 public class XmlRepository<T> : IRepository<T>
 {
    public void Add(T entity)
    {
       // XML dosyaya ekle...
    }

    public IList<T> GetAll()
    {
       // XML dosyadan oku...
    }
 }

Ancak bu iki farklı Repository tipinin, çalışma zamanında seçilebilir ve değiştirilebilir olması gerekmektedir. Aksi taktirde kodun değiştirilebilir olması istenmeyen bir durumdur. Bu değişime ayak uydurabilmek adına, değişikliği otomatik olarak gerçekleştirebilecek bir sınıfa ihtiyaç duyulmaktadır. Bu sınıf, çalışma zamanında dependency injection mekanizması ile yüklenebilen bir modül halinde tasarlanabilir.


 public class ApplicationRepositorySelectionModule : NinjectModule
 {
    public override void Load()
    {
        switch (ApplicationConfiguration.StorageType)
        {
           case PersistenceStorageType.SqlRepository:
              Bind(typeof(IRepository<>)).To(typeof(SqlRepository<>));
              break;
          case PersistenceStorageType.XmlRepository:
              Bind(typeof(IRepository<>)).To(typeof(SqlRepository<>));
              break;
         default:
              throw new ApplicationException("Not supported storage type!");

       }
    }
 }

NinjectModule sınıfı, Ninject dependenjy injector aracına ait bir sınıftır. Yaptığı işlem ise  Interface türlerine karşılık hangi somut sınıfın oluşturulacağını belirlemektir. Zamanı geldiğinde ilgili nesneyi oluşturup programa sağlamak yine Ninject tarafından gerçekleştirilmektedir.

Modül içerisinde kullanılan PersistenceStorageType ve ApplicationConfiguration sınıfları ise şu şekildedir.


 public class ApplicationConfiguration
 {
     public static PersistenceStorageType StorageType { get; set; }
 }

 public enum PersistenceStorageType
 {
     SqlRepository = 0,
     XmlRepository = 1
 }

Bu şekilde birden fazla repository sınıfı ile konfigurasyonu sağlababilir şekilde çalışmak mümkün olmaktadır. Yazılımda çevikliği yani yazılımın değişime ayak uydurabilme yeteneğini sağlayabilmek açısından uygulanabilecek olan küçük bir detaydan bahsetmiş olduk.

Bir sonraki yazıda görüşmek dileğiyle.

Asp.Net MVC Web API Projesinde Ninject ile Dependency Injection

5 Tem

Bir önceki yazılarımdan biri olan MVC Projesinde Dependency Injection başlıklı yazıda MVC uygulamasında Controller sınıfı içerisine dışarıdan bağımlılıkların enjekte edilmesini incelemeye çalışmıştık. Bu yazımızda ise Asp.Net MVC Web Api uygulaması üzerinde Dependency Injection işlemini uygulamaya çalışacağız.

MVC uygulamasında Controller sınıfları System.Web.Mvc.Controller tipinden türetilirken API Controller sınıfları System.Web.Http.ApiController tipinden türetilmiştir. Bu nedenle Web API üzerinde Dependency Injection uygularken bir önceki örnek uygulamadaki yöntemden daha farklı bir yöntem kullanacağız.

public class ValuesController : ApiController
{
     readonly IProductRepository productRepository;
     public ValuesController(IProductRepository productRepository)
     {
          this.productRepository = productRepository;
     }

     public IEnumerable<string> Get()
     {
         return productRepository.GetValues();
     }
}

API içerisine bağımlılıkları enjekte ederken IProductRepository interface tipini uygulayan(implemente eden) sınıfları göndermeye dikkat edeceğiz.

WEB API içerisinde Dependency Injection işlemini gerçekleştirmek için yine MVC’de olduğu gibi IoC container kütüphanelerinden faydalanmamız gerekiyor.

WEB API projelerinde Controller sınıflarının parametreli şekilde çalışabilmesi için bazı ayarlamaları yapmamız gerekecek. Bu ayarlamalardan biri, System.Web.Http alanında bulunan GlobalConfiguration statik sınıfındaki DependencyResolver özelliğinin düzenlenmesi olacaktır. Bu sayede WEB API, resolver mekanizmasını tanıyacaktır. Bu ayarlama Global.asax.cs dosyası içerisinde yapılmaktadır. Tanımlama:

public class WebApiApplication : HttpApplication
{
     protected void Application_Start()
     {
         // Diğer kodlar...
         GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(CreateKernel());
     }

     private IKernel CreateKernel()
     {
         IKernel kernel = new StandardKernel();

         kernel.Bind<IProductRepository>().To<ProductRepository>();

         return kernel;
     }

}

NinjectDependencyResolver adında bir sınıf hazırlıyoruz ve yukarıdaki gibi DependencyResolver özelliğine atıyoruz. DependencyResolver özelliği IDependencyResolver tipindedir. Bu sebeple NinjectDependencyResolver sınıfı da IDependencyReolver tipini uygulamalıdır.

public class NinjectDependencyResolver : NinjectDependencyScope, IDependencyResolver
{
      private readonly IKernel kernel;

      public NinjectDependencyResolver(IKernel kernel): base(kernel)
      {
          this.kernel = kernel;
      }

      public IDependencyScope BeginScope()
      {
          return new NinjectDependencyScope(kernel.BeginBlock());
      }
}

NinjectDependencyResolver sınıfını aynı zamanda NinjectDependencyScope sınıfından türetiyoruz. Bunun sebebi ise IDependencyResolver interface tipinin barındırdığı BeginScope() metodudur. Bu metodun bir şekilde doldurulması gerekmektedir. NinjectDependencyScope tipi de kendi oluşturmuş olduğumuz bir sınıf olacaktır. Bu sınıfı de şu şekilde oluşturabiliriz.

public class NinjectDependencyScope : IDependencyScope
{
    IResolutionRoot resolver;

    public NinjectDependencyScope( IResolutionRoot resolver)
    {
        this.resolver = resolver;
    }

     public void Dispose()
     {
        IDisposable disposable = resolver as IDisposable;

        if (disposable!=null)
        {
            disposable.Dispose();
        }

        resolver = null;
     }

     public object GetService(Type serviceType)
     {
         if (resolver==null)
         {
             throw new ObjectDisposedException("this", "This scope has been disposed");
         }

         return resolver.TryGet(serviceType);
     }

     public IEnumerable<object> GetServices(Type serviceType)
     {
         if (resolver == null)
         {

              throw new ObjectDisposedException("this", "This scope has been disposed");
         }

         return resolver.GetAll(serviceType);
     }

}

Son aşamayı da bu şekilde tamamladıktan sonra projemiz çalışabilir hale gelmiş demektir.

WEB API Sonuç
WEB API Sonuç

Projenin örnek kodlarını SkyDrive üzerinden paylaşıyorum.

Kaynak Kod: Burada