Scoped, Transient ve Singleton Yaşam Döngüleri ile Dependency Injection

SOLID prensiplerinin bize verdiği yetkiye dayanarak; clean code, reuseability vs. derken konu bir şekilde dönüp dolaşıp Dependency Injection’a da geliyor. Konu buraya gelince de, başlıktaki 3 kavramla karşılaşıyoruz.

services.AddSingleton<Covid19Vaccine>();

Peki nedir bu kavramlar birlikte görelim.

Singleton: Burası Single (tek) kelimesinden aklımızda kalsın. Singleton tanımlı servislerimiz, uygulama ayağa kalkınca bir defa oluşur ve uygulama ömrü boyunca aynı referans üzerinden bize hizmet eder. Bunun açıklaması aslında en basiti. Diğerlerinde iş biraz daha değişiyor.

Loglama, uygulama özelliğini açma kapama gibi genel uygulama durumunu kontrol etme amaçlı servislerin, her istek için yeniden oluşturulmasına gerek yoktur. Bundan dolayı bu tarz durumlarda singleton tercih edilebilir.

Başka bir Singleton daha var ama buyrun bununla idare edin 🙂

Scoped: Bu yaşam döngüsü her HTTP istek başı bir adet nesne üretmek için kullanılır. HTTP isteği sona erdiğinde ise Garbage Collector’un hışmına uğrayacaktır. Genel anlamda HTTP isteği ile ilgili bir state kontrol etmek ve de tutmak isterseniz scope yaklaşımı daha uygun olacaktır.

Bunu yetkilendirme, oturum yönetimi gibi kavramlar için kullanabilirsiniz.

Transient: Transient tanımlı servislerin, oluşturma ve yıkım maliyetlerinin oldukça minimum seviyede olmaları gerekmektedir. Çünkü transient servisler, ne zaman talep edilirse her defasında yeniden oluşturulur. Burada transient tanımladığımız servisler çok önemli. Eğer maliyetli servisleri transient tanımlar isek, GC esnasındaki bekletmeler, uygulamayı yanıt veremez duruma getirebilir. İki instanceın birbirinden bağımsız olması gereken durumlarda, state vs. kaygısı yok ise, transient kullanılabilir.

Teorisi Tamam Ama Koduna Da Bakalım

Öncelikle bir .NET 7.0 API projesi ve bir class library oluşturuyorum. Sınıf kütüphanemiz bizim API projemiz için yardımcı kütüphane olduğundan, kütüphaneyi, API projesine bind ediyoruz.

Sonrasında classlarımı ve interfacelerimi yardımcı kütüphanemde oluşturuyorum.

Tüm servislerimde bir Guid ve DateTime alabileceğim birer property ekliyorum. Hepsi aşağıdaki gibi.

Sonrasında ise somut classlarımda bunların karşılıklarını ve setlendikleri constructorları yazıyorum.

En son ise bunları .NET’in kendi DI lifetime yönetimine bırakmak için gerekli tanımlarımı yapıyorum.

Başka hiçbir şeyi değiştirmeden yeni bir controller oluşturarak, kendime bir endpoint yaratıyorum.

Bu sayede istek atarak, nesnelerimin tuttuğu değerler arasındaki değişimleri inceleyebileceğim. Bu şekilde projemi ayağa kaldırarak ilk isteğimi gönderiyorum. İlk isteğimin cevabı:

[ “SingletonDate”, “24.04.2023 18:28:27”
, “SingletonId”, “5239ece0-aadd-472a-a7ca-d7ea3202d618”
, “TransientDate”, “24.04.2023 18:28:27”
, “TransientId”, “48e81e4a-688c-4eb7–9275-c0731f9d5bd2”
, “ScopedDate”, “24.04.2023 18:28:27”
, “ScopedId”, “ab56fa34–4fa8–4725–9a66-e997c96fb145”
, “TransientDate2”, “24.04.2023 18:28:27”
, “TransientId2”, “1bf374fd-fcf9–4f9b-911e-9ee0cfc9b7d8”
, “ScopedDate2”, “24.04.2023 18:28:27”
, “ScopedId2”, “ab56fa34–4fa8–4725–9a66-e997c96fb145” ]

Görüldüğü üzere, ValueController isimli controllerımda tam 5 adet nesne talep ettim. Bunlardan 1 tanesi singleton, 2 tanesi transient ve 2 tanesi scoped yaşam döngüsüne sahip. Ancak görüyorum ki transient nesnemdeki ID’ler her bir nesnem için farklı iken, scoped tanımlı nesnemdeki idler değişmemişler. Tekrar bir istek atıyorum.

[ “SingletonDate”, “24.04.2023 18:28:27”
, “SingletonId”, “5239ece0-aadd-472a-a7ca-d7ea3202d618”
, “TransientDate”, “24.04.2023 18:31:32”
, “TransientId”, “7f54b383–58a1–46ee-a957-a968441650c6”
, “ScopedDate”, “24.04.2023 18:31:32”
, “ScopedId”, “ed697ddc-b5c6–4257–9982–5a231c6d8f83”
, “TransientDate2”, “24.04.2023 18:31:32”
, “TransientId2”, “fcb594ed-4343–4f03–8e69–06a921dc430f”
, “ScopedDate2”, “24.04.2023 18:31:32”
, “ScopedId2”, “ed697ddc-b5c6–4257–9982–5a231c6d8f83” ]

İkinci istekte de görülüyor ki, singleton yaşam döngüsüne sahip nesnemin ID’si ve tarihi değişmemiş. Bu da uygulama yaşam döngüsü boyunca kaç defa çağırırsam çağırayım değişmeyecek olduğu görülüyor. Ancak scoped yaşam döngülü nesnemin idlerine baktığım zaman 2. istek için ikisinin de aynı, ilk istekten farklı olduğunu görüyorum. Bu da her HTTP isteğinde scoped nesnemin tekrar oluşturulduğunu bana gösteriyor. Transient ise görüldüğü üzere burada da ilk istekte olduğu gibi farklı görünmekte.

Bu şekilde singleton, transient ve scoped yaşam döngülerinizi DI containerlarınızda ihtiyaca ve performans kaygılarınıza göre şekillendirebilirsiniz.

Projeyi incelemek isterseniz buyrun: https://github.com/idylmz/DISample

Similar Posts

  • |

    Projeyi Canlıya Almak

    Her yazılımcı günün birinde projesini canlıya alacaktır. Bugüne kadar hosting modellerini kullanan ben, günün birinde farklı disiplinlere geçmeye karar verdiğimde bir şey farkettim. Her projem için farklı konfigürasyonlarda hosting hizmeti almaya başladım. Aslında yazılım serüvenim .Net ile başladığından, tek bir hosting hizmeti işimi görüyodu. Ancak sonrasında biraz daha JS taraflarına kaymaya başladım ve oradaki projelerimi de…

  • |

    JMX ile Java Uygulamalarını İzlemek

    https://github.com/idylmz/JMXExampleProject Yıllar önce resilience üzerine çalışan bir ekibe katıldığımda, Java ile geliştirilmiş bir ürünü APM ajanı olmadan izlememiz istenmişti. Ekipteki herkesin kafasında tek bir soru vardı: “Agent kurmadan bu uygulama içinde neler olup bittiğini nasıl göreceğiz?” Ürün dış bir ekibin geliştirmesi olduğu için, izleme konusunu onlara danıştık. Aldığımız cevap ise kısaydı: “JMX ile bağlanabilirsiniz.” O dönem ne…

  • OpenTelemetry ve Zipkin Exporter İle .NET Uygulama Tracelerini İzlemek

    Gereklilikler: Docker, .NET 7.0 Uygulamaları geliştirirken productionda uygulamayı izlemek de önemli. Gerek metrikleri, gerekse de traceleri incelemek için bolca açık kaynak çözüm mevcut. Bunlar da kendine has şekillerde koda implement edilebiliyor. .NET 7.0 ile birlikte OpenTelemetry implementasyonu için de kolaylık sağlandı. Bu sayede OpenTelemetry’yi sadece bootstrap aşamasında konfigüre ederek metrikleri ve traceleri toplamaya başlıyoruz. Tabi traceleri sadece…

  • C# İle Cross Platform

    Blazor 101 “Ben iOS’çuyum, ben Android’çiyim” anlayışının son bulmaya başladığı bu zamanda, artık “Ben mobilciyim ben webçiyim” anlayışı da çoğu dilde son bulmaya başlıyor. Özellikle JS topluluklarının geliştirmiş oldukları kütüphanelere ve frameworklere bakarak, Microsoft’un bu anlayışı ne kadar geç benimsediği de ortada. Belki Java ve Python cephesinde farklı şeyler de vardır. Alanım olmadıkları için yorum…

  • C# ile Cross Platform Part II

    Blazor Hybrid ve Blazor WASM ile cross-platform uygulama Neler yapılabildiğini gösterdim. Şimdi de nasıl yapılıra geliyoruz. Yazının sonunda anlattıklarımın toparlanmış halinin reposunu bulabilirsiniz. Giriş Merhabalar tekrardan. Daha önceden Blazor ile neler yapıldığından bahsetmiştim. Şimdi de bu yazıda nasıl yapıldığı kısmına geliyorum. Yazının sonunda ise tek bir kod yazarak Web, MacOS, Windows, iOS ve Android için…

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir