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

ASP.NET MVC Projesinde Dependency Injection Uygulanması

30 Haz

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

ASP.NET Core geliştiriciler için yol haritası

5 Oca

2019 yılında, bir grup geliştirici, GitHub‘da ASP.NET Core geliştiriciler için bir yol haritası ortaya koymuşlar. Kaynağa buradan ulaşabilirsiniz.

Bu yazıda, her geliştirici için faydalı olabileceğini düşündüğüm bu yol haritasını sizlerle paylaşmak istedim.

Yol Haritası Boyunca Bilinmesi Gerekenler

  1. Öncelikle bilinmesi gerekenler.
    • C#
    • Entity Framework
    • ASP.NET Core
    • SQL Fundamentals
  2. Bilinmesi gereken genel geliştirme becerileri.
    • GIT sistemi öğrenilmeli, GitHub üzerinde yeni bir repository oluşturulabilmelidir, kod diğer geliştiricilerle paylaşılmalıdır.
    • HTTP(S) protokolü bilinmeli, http request metodları (GET, POST, PUT, PATCH, DELETE, OPTIONS) bilinmelidir.
    • Google kullanmaktan ve araştırmaktan korkmayın.
    • Dotnet CLI öğrenmelisiniz.
    • Veri yapıları ve algoritmalar hakkında bir kaç kitap okumalısınız.
  3. Dependency Injection (DI – Bağımlılıkların dışarıdan alınması)
  4. Veritabanları
  5. Cache Mekanizmaları
  6. Log Mekanizmaları
  7. Web site geliştirme şablonları (Template Engines)
  8. Gerçek zamanlı iletişim araçları (Realtime Communication)
  9. Nesne eşleştirme araçları (Object Mapping)
  10. API istemcileri (Clients)
  11. Bilinmesi faydalı olabilecek bilgiler
  12. Testler
  13. Görev zamanlayıcılar (Task scheduling)
  14. Mikro servisler (MicroServices)
  15. SOLID prensipleri
  16. Tasarım Kalıpları (Design-Patterns)

Yol Haritası Görseli

Angularjs Proje Yönetimi

8 Eyl

Yazılım projelerinin geliştirilmesi sırasında karşılaşılan bazı genel problemler vardır. Bu problemler yazılımın Frontend veya Backend olmasına bağlı olmayan, sürecin gelişimi sırasında ortaya çıkan problemlerdir.

Projelerde istenen taleplere bağlı olarak yazılımda çok fazla kod olabilir. Kod sayısı arttıkça yazılımın çalışma performansı da düşmeye başlar. Bir süre sonra kodu yönetemez hale gelirsiniz. Artık kod sizi yönetmeye başlar ki bu durumda yeterki  çalışsın mantığıyla bir dizi mantıksız işler yapmaya başlayabilirsiniz. Bu gibi durumlarla başa çıkabilmek için uyguladığınız yöntemlerde kod sayısı artsa bile kodda karmaşıklığın oluşmaması gerekmektedir. Yani bir sene süren bir projede ilk gün nasıl kafa karışıklığı olmadan rahatça kod eklenebiliyorsa, son günde de aynı rahatlıkla kod eklemesi yapılabilmelidir. Modüler yapılar kullanarak bir şekilde kodun karmaşasını azaltabiliriz, bu sefer de modül sayıları artar ve iş süreleri uzamaya başlar.

Bu noktada işlerimizi önemli ölçüde kolaylaştıracak olan araçlar Framework’lerdir. Bizim yapmamız gereken bir takım işleri Framework’lere yüklemek zaman kazanmak açısından önemlidir. Her framework amaca uygun olmayabilir. Bu nedenle Framework seçiminde kolay kullanılabilirlik, sürekli güncellenme, performans ve geniş topluluklar tarafından kullanılıyor olmak önemlidir.

Angularjs bu açıdan bakıldığında yapılabilecek en doğru seçimlerden birisidir. Üretim ve destekleme tarafında Google vardır ve çok yaygın kullanılan bir Framework’dür. Kullanım açısından son derece kolaydır. Model ve View tarafındaki ayrımı yapabilmesi (MVC mimarisi) ve modüler geliştirmeye imkan sağlayan yapısı sayesinde kullanıcı dostu bir yapısı vardır.

Angularjs Yapı Taşları

Angularjs kendine özgü bir mimari üzerine geliştirilmiştir. Belli yapı taşları üzerine oturtulmuş bir düzen söz konusudur. Bunlar:

  • Module
  • Config
  • Route
  • Controller
  • View
  • Directive
  • Filter
  • Service
  • Factory

şeklinde sıralanabilir.

Angularjs Proje Yapılandırması

Angularjs ile yapılandırılacak projeler mimari açıdan önemlidir. Biz geliştiricilere düzgün kod yazabilmek için birçok imkanı sunan bir framewrok ile spagetti kod oluşturmamak lazım. Bu açıdan angularjs ile çalışırken dikkat edilmesi gereken bazı hususları aşağıda başlıklar halinde ele alınmıştır.

Modüler Yapı

Müşterinin her talebi için uygulamayı bölümlendirmek ve her bölüm için farklı bir modül oluşturulmalıdır. Geniş ölçekli bir uygulama geliştirirken her bileşeni tek bir modül altına toplamak yerine iş mantığına göre tasarlanmış birden fazla modül ile çalışmak daha uygun olacaktır. Örnek olarak Email Hizmeti veren bir uygulama için modüller şu şekilde olabilir:

angular.module("Epostalar", []);
angular.module("GelenKutusu", ["Epostalar"]);
angular.module("EpostaServisi", ["GelenKutusu"]);

Model Servisleri

Angularjs tarafından sunulan Dependency Injection yapısı sayesinde soyutlamalar kolayca yapılabilmektedir. Servis yapısı ile modüller arasında izolasyonlar yapılmalıdır. Bu sayede servisler veya modüller arasında kod aktarımı ile iletişim sağlanabilir.

Oluşturulan servisler tek bir görevi yerine getirmelidir. Örneğin HTTP protokolü üzerinden bir dış kaynak ile veri alış verişi yapacak olan bir servis sadece o kaynakla konuşmalıdır. Veriyi almışken servise hadi ekranda listeleme de yapın şeklinde ikinci bir görev verilmemelidir. Aksi taktirde hep karşısında durduğumuz karmaşıklık problemine doğru ilk adımı atmış oluruz.

Kod Yapısı

Mümkün olduğunca az kod satırlarıyla hazırlanmış, gerektiğinde servisler aracılığı ile haberleşebilen modüller oluşturulmalıdır. Servis, Controller ve Template gibi kod birimlerinin içerikleri sade anlaşılır ve kısa tutulmalıdır.

HTML tarafındaki bir DOM elemanları üzerinde Controller veya Service gibi yapılar içinden erişip doğrudan işlem yapmamalısınız.

Controller sınıflarından dış kaynaklara erişilmemelidir. Bu işlemi servisler aracılığı ile gerçekleştirip, ilgili servislere controller tarafından erişim sağlanmalıdır. Veri kümelerinin controller içerisinde depolanması da yanlış bir davranıştır.

Görünüm Yapısı

Görünüm tarafındaki HTML elementlerini depoladığımız yapılara template denir. Template içerisinde sadece HTML kodları ve Angularjs direktifleri olmalıdır. İş kuralları bu kısımda tanımlanmamalıdır. Kurallar template tarafından erişilen controller içerisinde tanımlanmalıdır. Aksi taktirde görünümle alakası olmayan kural belirleme sorumluluğu controller tarafından alınıp görünüm tarafına yüklenmiş olur.

Görünüm tarafında sürekli güncellenmesi gerekmeyen içerikler için TwoWayBinding yerine OneWayBinding tercih edilmelidir.

Proje Dizin Yapısı

Proje yapısı şekillendirilirken dikkat edilmesi gereken bir diğer yapı ise proje dizin yapısının oluşturulmasıdır. Kod birimlerinizi HTML, CSS, JS gibi özelliklerine ve Angularjs yapılarına göre ayırmak ve dizinlere aktarmak sık kullanılan bir yöntemdir.

Dizin
Yanlış Dizin Yapısı

Bütün controller dosyalarını Controllers dizini altında dizini altında toplamak, zamanla dizin içerisinde onlarca belki yüzlerce dosya birikmesine neden olacaktır. Bu durumda aradığımızı bulmak daha fazla zaman alacaktır. Örneğin bir EmailApplication projesi için GelenKutusu modülünün controller kodu Controllers dizininde aranacak ve görünüm için hazırlanan template kod dosyası ise Templates dizininde aranacaktır. Bu şekildeki proje tasnifi “türe göre tasnif” olarak adlandırılır. Türe göre tasnif edilen projeler zamanla projelerin karmaşık bir hal almasına neden olur.

Bunun yerine iş mantığına göre planlanmış bir dizin yapısı oluşturmak daha uygun bir yöntem olacaktır.

Uygun Dizin Yapısı
Uygun Dizin Yapısı

Email hizmeti ile ilgili iş kurallarını ve dosyalarını tabakalandırarak çalışmak daha uygun bir seçim olacaktır. Bu şeklide proje tasnifine ise “özelliğe göre tasnif” denir. Bu durumda Email listemizdeki kişilerle ilgili işlemlerin Contacts dizininde olduğunu özellik bakımından kolayca anlayabiliriz. Hem görünüm hem kullanım açısından sade ve anlaşılır bir yöntemdir.

Kodun organizasyon yapılandırması tamamen ekibinize veya size kalmış bir seçimdir. Bir dayatma söz konusu değildir. Temel nokta, kodun iyi bir şekilde ayrıştırılması ve ayrıştırılan bölümlerin yeni bir karmaşaya yol açmamasıdır.

Bu yazıda angularjs projeleri oluşturulurken dikkat edilmesi gereken önemli hususlardan bahsetmeye çalıştık. Umarım faydalı olmuştur. Bir sonraki yazıda görüşmek dileğiyle.