Open
Dependency Injection

Martin Fowler'ın geliştirdiği bir prensipdir.
Dependency Injection (Bağımlılık Enjeksiyonu),bağımlı parçaların birbirinden ayrılıp bunların dışarıdan enjekte edilmesi ve böylelikle sistemdeki bağımlılıkların azaltılmasıdır. Aradaki ilişkiyi gevşek tutmak, ilerde yapacağınız değişiklikler açısından önemlidir.
Örneğin, A sınıfında, B sınıfı nesnesi üretildi.Böylelikle A , B'ye bağlı hale geldi.İlerde B sınıfında bir değişiklik yaparsanz, A sınıfında da yapmanız gerekir.İşte bu bağımlılığı olabildiğince minimuma indirgeyeceğiz.

//Hatalı yaklaşım
public class Student
{
   private DbFacade facade;
   public Student()
   {
    facade = new DbFacade();
   }
 ....
}

Dependency Inversion prensibine göre;

(a)Modüller birbirine bağlı olmamalı. Her ikisi de soyut (abstract) kavramlara bağlı olmalıdır. Bağımlılıklar, soyutlaştırılmalıdır.Bunun için interface veya abstract class kullanmalıyız.Interface ve ya abstract kullanarak sınıflar arasında geçiş yapmalıyız. Böylece sürdürülebilir bir yazılım projesi geliştirmiş oluruz.
(b)Inversion of Control(IoC) prensibine göre bağımlılıkları oluşturmanın kontrölü, dışarıdan olmalıdır. Dependency Injection, IoC prensibini implement eden bir design patern olduğu için bağımlılıklar class’a dışarıdan “enjekte” edilir. Kullandığımız sınıfta, farklı bir sınıfın nesnesini kullanıcaksk new anahtar sözcüğünü kullanmayız. Bu nesneyi Contructor ya da Setter metoduyla, parametre olarak alırız.
public class Student
{
  private IdbFacade _facade;
  public Student(DbFacade prm)
  {
   this._facade = prm;
  }
  ....
}
ASP.NET Core, bağımlı sınıfların nesnelerini, IOC konteynerı kullanarak enjekte eder.IOC konteyner 3 tür servis yönetir.Singleton: IoC konteyneri, uygulamanın ömrü boyunca tek bir servis örneği oluşturur ve paylaşır.Transient: IoC konteyneri, her istediğinizde belirtilen servis türünün yeni bir örneğini oluşturur.Scoped: IoC konteyneri, istek başına bir kez belirtilen hizmet türünün bir örneğini oluşturur ve tek bir istekle paylaşır.



Dependency Injection Örneği


//Model Katmanındaki bir Table Entity
    public class E_Table
    {
        [Key]
        public int ID { get; set; }
        public string Name { get; set; }
        public string ImageUrl { get; set; }
        public double? Price { get; set; }
    }

Dal Katmanımızda 2 adet klasörümüz var. Abstract (Soyut) ve Concrete (somut).

  public  interface ITableRepository
    {
        IEnumerable<E_Table> GetAll();
    }
    public class TableRepository : ITableRepository
    {
        private WebDbContext context;
        public cTableRepository(WebDbContext prm)
        {
            context = prm;
        }
        public IEnumerable<E_Table> GetAll()
        {
            return context.Tbl_Table;
        }
    }

Controller ile View'e taşıyalım ve alıştırmamızı Tarayıı üzerinde görelim.

        private ITableRepository repo; //gerçek repository’ler yerine mock repository’lerin kullanacağız.
        public HomeController(ITableRepository prm)
        {
            repo = prm;
        }
        public IActionResult Index()
        {
            return View(repo.GetAll());
        }
    
   public void ConfigureServices(IServiceCollection services)
   {
    services.AddDbContext<WebDbContext>();
    services.AddTransient<ITableRepository, TableRepository>();  //ITable çağırdığımızda, Table sınıfı gönderilecek.
    
   }       
@model IEnumerable<E_Table>

@foreach (var item in Model)
{
    @Html.DisplayFor(modelItem => item.Name) 
    <img src="~/images/@item.ImageUrl" width="80" height="40"/> 
    @:
}



Generic Repository ile Dependency Injection


//Model Katmanındaki bir Table Entity
    public class E_Table
    {
        [Key]
        public int ID { get; set; }
        public string Name { get; set; }
        public string ImageUrl { get; set; }
        public double? Price { get; set; }
    }

Dal Katmanımızda 2 adet klasörümüz var. Abstract (Soyut) ve Concrete (somut).İlk Generiklerimizi oluşturalım.

    public interface IGenericRepository<T> where T: class
    {
        IEnumerable<T> GetAll();
    }
    public class GenericRepository<T> : IGenericRepository<T> where T : class
    {
        protected readonly DbContext context;
        public GenericRepository(DbContext prm)
        {
            context = prm;
        }
        public IEnumerable<T> GetAll()
        {
            return context.Set<T>().ToList();
        }
    }

Sonra Tablo isimlerimizden istifade edelim.


  public  interface ITableRepository:IGenericRepository<E_Table>
    { 
    }

    public class TableRepository : GenericRepository<E_Table>, ITableRepository
    {
        public TableRepository(WebDbContext prm) : base(prm)
        {
        }
    }
        private ITableRepository repo;
        public HomeController(ITableRepository prm)
        {
            repo = prm;
        }
        public IActionResult Index()
        {
            return View(repo.GetAll());
        }
    
   public void ConfigureServices(IServiceCollection services)
   {
    services.AddDbContext<WebDbContext>();
    services.AddTransient<ITableRepository, TableRepository>();  //ITable çağırdığımızda, Table sınıfı gönderilecek.
   }       
@model IEnumerable<E_Table>

@foreach (var item in Model)
{
    @Html.DisplayFor(modelItem => item.Name) 
    <img src="~/images/@item.ImageUrl" width="80" height="40"/> 
    @:
}



Not:Eğer Extra bir metot geliştirmek istesek bunu ilgili tablonun interface'ine ilave edebiliriz.Örneğin;

  public  interface ITableRepository:IGenericRepository<E_Table>
    { 
     IEnumerable<E_Table> GetAllTableExtraPrm();
    }

    public class TableRepository : GenericRepository<E_Table>, ITableRepository
    {
        public TableRepository(WebDbContext prm) : base(prm)
        {
        }

        public WebDbContext ctx
        {
            get { return context as WebDbContext; }
        }

        public IEnumerable<E_Table> GetAllTableExtraPrm()
        {
            return ctx.Tbl_Table;
        }
    }




Dependency Injection Lifetimes

Scoped, Singleton, Transient

Singleton ile inject edilmiş Dependency, uygulama ilk kez ayağa kalktığında instance yaratır ve uygulama stop olana kadar bu instance 'ı kullanır.

Scoped ise her istekte yeni bir instance alır.

Dependency injection lifetime container'dan, istenen objenin ne zaman instance create edileceğini söyler.Her zaman aynı örneği verir.

Scoped : Tek bir instance yaratan lifetimedır. Containerda tutar ve lifecyle obyunca hep aynı instance ı kullanır.yani Request içinde hep aynı sınıf örneğini ver.

Transient: Bu lifetime ise ilgili obje her istendiğinde yeni bir instance yaratır.Her zaman yeni sınıf örneği ver.Bağlayıcılığı en azdır.

02.02.2020