.NET Core - Dependency Injection - Oluşturulan Nesnelerin Yaşam Sürelerini Anlamak (Singleton,Scoped,Transient)

 .NET Core projelerinde, oluşturulan nesnelerin belirli bir yaşam süreleri bulunur. Bunları anlamak için önce Dependency Injection prensibinden kısaca bahsetmek gerekir.

Dependency Injection, projelerimizde bulunan bağımlılıkları yönetebildiğimiz, nesneleri bağımlılıktan kurtaran, değişiklik yapmamız gerektiğinde minimum değişiklikle düzenleme yapabileceğimiz bir prensiptir.

Örneğin .NET Core projemizde, veri tabanında yeni bir teknoloji kullanacağımız zaman (Oracle -> Microsoft Sql Server) ya da log yazma yöntemimiz değişirse (metin belgesi -> veri tabanı) eğer dependency injection prensibi kullanmışsak Startup.cs dosyasında tek satır kodla bu bağımlılığı yönetebiliyoruz. En iyi yöntem olarak genel bir interface tanımlayıp interfaceleri bu sınıflara implement ettikten sonra controller/servis metotlarına enjekt etmektir.

Dependency Injection prensibini uygularken, nesneleri ne zaman ve tekrardan oluşturup oluşturulmayacağını belirlememiz gerekir. Bu zamanlamaya yaşam süresi - service lifetimes denir.

.NET Core'da yaşam süresi kavramını üç farklı yolla açıklayabiliriz. Bu üç tekniği projelerde ihtiyacımıza göre tanımlayabiliriz. 

  • Singleton 
Singleton ile oluşacak nesne örneği (instance) bir tanedir ve uygulama çalıştığı sürece aynı nesne kullanılmaya devam eder. Her istekte aynı nesne kullanılır. Startup.cs dosyasında AddSingleton metodu ile tanımlama yapılır.

  • Scoped
Scoped ile her istekte yeni bir nesne örneğinin oluşması ve aynı istek boyunca bu nesne kullanılmaya devam eder. Eğer sayfa yenilendiğinde, yeni bir istek olacağı için yeni bir instance oluşturulur. Startup.cs dosyasında AddScoped metodu ile tanımlama yapılır.

  • Transient
Transient ile oluşturulmuş nesnenin her seferinde tekrardan örneğinin oluşturulması sağlanır. Her enjekte edilmesinde veya istekte yeniden instance oluşturulur. Startup.cs dosyasında AddTransient metodu ile tanımlama yapılır.


Bu yaşam sürelerini örneklemek gerekirse, ASP.NET Core MVC projesinde StudentService sınıfı ve IStudentService interfacesi oluşturuldu. 


IStudentService interfacesi ise GetStudentId metodunu tutsun. Yaşam süreleri için  ISingletonStudentService, ITransientStudentService, IScopedStudentService interfaceleri oluşturulup IStudentService'yi implement edecektir.


StudentService ise yaşam sürelerinin için oluşturulan bu üç interface'yi de kullanacaktır. Bir de constructorda uyarı olarak da log nesnesi kullandık. Amacımız Output penceresinde constructor bloğuna girdiğini görüp, yaşam sürelerinin çalışma mantığının anlaşılmasıdır. 

Startup.cs dosyasında ConfigureServices metodunda yaşam döngülerimizi aşağıdaki görseldeki gibi tanımladık. 


Kurgumuzu oluşturduktan sonra Controller (HomeController) sınıfında servis enjeksiyon işlemine geçebiliriz. Constructor tarafında gerekli enjeksiyonlar yapıldıktan sonra View tarafında kullanılmak üzere ViewBag'lere atama yapılır. 
  • Transient için aşağıdaki kodları kullanıyoruz. 

Uygulamayı ayağa kaldırdıktan sonra değerler aşağıdaki gibidir. Her enjekte edilmesinde veya istekte yeniden instance oluştuğu için farklı değerler gördük. 

İlk istekteki değerler


Sayfa yenilendikten sonraki değerler


Visual Studio'da Output ekranındaki görünümde transient olarak nesne kullanıldığında uyarı loglanmaktadır. Sayfa yenilendiğinde her iki transient instanceleri için de uyarı yazmaktadır.

  • Scoped için aşağıdaki kodları kullanıyoruz. 


Uygulamayı ayağa kaldırdıktan sonra değerler aşağıdaki gibidir. İlk request için tek bir instance ile çalışmaya başladı. Bu yüzden iki değer de aynıdır. Sayfa yenilendikten sonra, yeni bir istek olduğu için değerler değişmiştir. AddScoped metodunun çalışma prensibi, tek bir request boyunca aynı instancenin kullanılmasıdır.

İlk istekteki değerler


Sayfa yenilendikten sonraki değerler


Visual Studio'da Output ekranındaki görünümde scoped olarak nesne kullanıldığında uyarı loglanmaktadır. Sayfa yenilendiğinde aynı requestte tek instance olduğu için tek log yazılmıştır.

  • Singleton için aşağıdaki kodları kullanıyoruz. 

Uygulamayı ayağa kaldırdıktan sonra aynı instance, uygulama ayakta iken hayatta olacaktır. 

İlk istekteki değerler ve sayfa yenilendikten sonraki değerler aynıdır. 


Visual Studio'da Output ekranındaki görünümde scoped olarak nesne kullanıldığında uyarı loglanmaktadır. Sayfa yenilendiğinde aynı requestte tek instance olduğu için tek log yazılmıştır.


Özet

 .NET Core projelerinde, oluşturulan nesnelerin belirli bir yaşam süreleri bulunduğunu ve dependency injection prensibine kısaca değinerek örnek bir proje üzerinde yaşam sürelerinin çalışma mantığından bahsettim.

Projeye ait Github linkine tıklayarak  kodları inceleyebilirsiniz. Keyifli okumalar :)

Yorumlar