Asp.NET Core 2 MVC’de Dependency Injection

Merhaba,

.NET mimarisi devrim niteliğinde .NET Core mimarisine yaptığı geçişle Asp.NET Core mimarisinde de oldukça radikal boyutta değişikliklerle bir tek IIS yahut platform bağımlılığından kendini soyutlamamakta, programatik açıdan da tüm bağımlılığa aykırı olan Dependency Injection alt yapısında bir yaklaşım sunmaktadır. Bu içeriğimizde Asp.NET Core 2 MVC projesinde Dependency Injection mantığını inceleyecek ve teknik boyutta bu bağımlılığı yönetmemizi sağlayan üç farklı yordamı tek tek değerlendirerek ihtiyaca dönük farklarını mukayese neticesinde netleştirip makalemizi noktalayacağız.

Asp.NET Core 2 MVC mimarisinde bir sınıfın constructer metodundan talep edilen parametreye gönderilecek nesneleri alt yapısal olarak Dependency Injection özelliği sayesinde önceden belirleyebiliyoruz ve yapısal olarak ilgili sınıftan üretilecek instancelarda parametredeki referans tipine olan bağımlılığı ortadan kaldırabiliyoruz.

Bu teoriği gözünüzde daha da canlandırabilmek için aşağıdaki örneklendirelim.
Varsayalım ki, elimizde bir interface’imiz olsun.

    public interface IOperation
    {
        string GetValue();
    }

Bu interface’den aşağıdaki gibi bir Controller sınıfının constructerından parametre ile nesne talep ettiğimizi düşünelim.

    public class HomeController : Controller
    {
        IOperation _operation;
        public HomeController(IOperation operation)
        {
            _operation = operation;
        }
        public IActionResult Index()
        {
            ViewBag.Value = _operation.GetValue();
            return View();
        }
    }

Bu şekilde ilgili projeyi derleyip çalıştırdığımız zaman “_operation” referansının null olduğuna dair bir hata ile karşılaşacağız. Doğrusu şu durumda bu hatayı almamız gayet doğal. Çünkü compiler bize “babacığım bu IOperation tipinden _operation referansının nesnesini vermeden kullanamazsın” demektedir. Dolayısıyla bizim böyle bir durumda ilgili tipte bir talep geldiği zaman “şu” nesneyi gönder dememiz ve tipe olan bağımlılığı soyutlamamız gerekmektedir.

Bu işlem için projede ki “Startup.cs” sınıfı içerisinde “ConfigureServices” metodunda aşağıdakine benzer bir çalışma gerçekleştirmemiz yeterli olacaktır.

.
.
.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<IOperation, Operation>();

            services.AddMvc();
        }
.
.
.

Dikkat ederseniz “services” parametresine generic “AddTransient” metodu ile “IOperation” tipinden gelen taleplerde “Operation” nesnesi döndürmesini belirtmiş bulunuyoruz. Tabi burada “Operation” nesnesi “IOperation” interface’inden aşağıdaki gibi türemesi şartıyla…

    public class Operation : IOperation
    {
        string _value = "Operation";
        public string GetValue() => _value;
    }

Bu işlemden sonra projeyi derleyip çalıştırdığınızda “Home(Controller).cs” controllerının constructerından talep edilen “IOperation” tipinden parametreye “Operation” nesnesi sistem tarafından direkt döndürüleceğinden dolayı hatasız olarak açılacaktır.

Bu noktada aklınızdan La hoca! ya Operation nesnesininde constructerı parametre alıyorsa? sorusunun geçtiğini duyar gibiyim… Tamam… Diyelim ki dediğiniz gibi düşünelim ve “Operation” sınıfı constructerında aşağıdaki gibi parametre alıyor olsun.

    public class Operation : IOperation
    {
        public Operation(string value) => _value = value;
        string _value = "Operation";
        public string GetValue() => _value;
    }

İşte böyle bir durumda “Startup.cs” sınıfında;

.
.
.
        public void ConfigureServices(IServiceCollection services)
        {
            //services.AddTransient<IOperation, Operation>();
            services.AddTransient<IOperation>(i => new Operation("Constructer value"));

            services.AddMvc();
        }
.
.
.

şeklinde çalışmamızı gerçekleştirebiliriz. Burada “IOperation” tipinden bir talepte bulunulduğu zaman “şu” nesneyi şu ayarlarda gönder demiş bulunmaktayız.

Bu noktaya kadar Asp.NET Core 2 MVC’de Dependency Injection yaklaşımının nasıl olduğunu değerlendirmiş ve sanırım netleştirmiş olduk. Şimdi “Startup” sınıfı içerisindeki “ConfigureServices” isimli metot içerisinde uygulamaya dahil edilen nesneleri “AddTransient” fonksiyonu dışında “AddScoped” ve “AddSingleton” fonksiyonları aracılığıylada dahil edebilmekteyiz. Şimdi gelin bu metotların arasındaki farklar nelerdir? sorusunun cevabını inceleyelim.

AddTransientAddScopedAddSingleton
Her talepte yeni ve geçici bir nesne üretir.Bir talebe/request özel nesne üretir. Sadece o requeste özel nesne oluşturulur.Her talep için ilk üretilen nesneyi döndürür. Uygulamanın her noktasından üretilmiş mevcut nesneye erişilir.

Şimdi bu metotları örneklendirmek için özel interface yapıları oluşturalım.

    public interface IOperationTransient : IOperation
    {
    }
    public interface IOperationScoped : IOperation
    {
    }
    public interface IOperationSingleton : IOperation
    {
    }

Örneklendirmeyi genelleştirilmiş yapabilmek için “Operation” nesnemizi bu interfacelerden türetelim ve bir yandan da boş constructer oluşturalım.

    public class Operation : IOperation, IOperationTransient, IOperationScoped, IOperationSingleton
    {
        public Operation() { }
        public Operation(string value) => _value = value;
        string _value = "Operation";
        public string GetValue() => _value;
    }

Bu oluşumlardan sonra “Home(Controller).cs” isimli controller sınımıfızın controllerında aşağıdaki gibi nesne taleplerinde bulunalım.

    public class HomeController : Controller
    {
        IOperation _operation;
        IOperationTransient _operationTransient;
        IOperationScoped _operationScoped;
        IOperationSingleton _operationSingleton;
        public HomeController(IOperation operation,
            IOperationTransient operationTransient,
            IOperationScoped operationScoped,
            IOperationSingleton operationSingleton)
        {
            _operation = operation;
            _operationTransient = operationTransient;
            _operationScoped = operationScoped;
            _operationSingleton = operationSingleton;
        }

        public IActionResult Index()
        {
            ViewBag.ValueOperation = _operation.GetValue();
            ViewBag.ValueOperationTransient = _operationTransient.GetValue();
            ViewBag.ValueOperationScoped = _operationScoped.GetValue();
            ViewBag.ValueOperationSingleton = _operationSingleton.GetValue();
            return View();
        }
    }

Şimdi bu taleplere karşı ilgili nesnelerini gönderelim.

.
.
.
        public void ConfigureServices(IServiceCollection services)
        {
            //IOperation tipine varsayılan nesne tipi atıyoruz.
            services.AddTransient<IOperation, Operation>();
            services.AddTransient<IOperationTransient, Operation>();
            services.AddScoped<IOperationScoped, Operation>();
            services.AddSingleton<IOperationSingleton, Operation>();

            services.AddMvc();
        }
.
.
.

Bu şekilde projeyi derleyip çalıştırdığımızda, kullanılan fonksiyonun işleyişine göre her bir tipe özel nesne üretilip talebin olduğu noktaya gönderilecektir.

Üretilen nesnelerin hangi fonksiyonellikle üretildiklerini tasdiklemek için aşağıdaki gibi bir çalışmada gerçekleştirilebilir.

.
.
.
        public void ConfigureServices(IServiceCollection services)
        {
            //IOperation tipine varsayılan nesne tipi atıyoruz.
            services.AddTransient<IOperation>(i => new Operation($"Created for {nameof(IOperation)}"));
            services.AddTransient<IOperationTransient>(i => new Operation($"Created for {nameof(IOperationTransient)}"));
            services.AddScoped<IOperationScoped>(i => new Operation($"Created for {nameof(IOperationScoped)}"));
            services.AddSingleton<IOperationSingleton>(i => new Operation($"Created for {nameof(IOperationSingleton)}"));

            services.AddMvc();
        }
.
.
.

“Index.cshtml” dosyamızda da aşağıdaki gibi çalışma yaparsak eğer;

<h3>@ViewBag.ValueOperation</h3>
<h3>@ViewBag.ValueOperationTransient</h3>
<h3>@ViewBag.ValueOperationScoped</h3>
<h3>@ViewBag.ValueOperationSingleton</h3>

projeyi derleyip çalıştırdığımızda aşağıdaki ekran görüntüsünde olduğu gibi sonuçla karşılaşacağız.
Asp.NET Core 2 MVC'de Dependency Injection

Buradan da anlaşılan her bir nesne amacına uygun bir şekilde Dependency Injection alt yapısıyla üretilmektedir. Bu yapı bizlere mükemmel tasarım esneklik sağlamakta ve lüzumsuz kod yapısından da mümkün mertebe arındırmaktadır.

İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…

İyi çalışmalar…

Bunlar da hoşunuza gidebilir...

Bir cevap yazın

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

*

Copy Protected by Chetan's WP-Copyprotect.