Furkan KapukayaYazılım geliştirme
C# ve .NET2 dk okuma

.NET'te Dependency Injection: Servis Ömürleri ve Sık Yapılan Hatalar

.NET'te bağımlılık enjeksiyonunun mantığı, Singleton, Scoped ve Transient servis ömürleri, constructor injection, keyed services ve kaçınılması gereken yaygın hatalar.

Dependency Injection (DI, bağımlılık enjeksiyonu), bir sınıfın ihtiyaç duyduğu nesneleri kendisinin oluşturması yerine dışarıdan almasıdır. .NET'te DI, ASP.NET Core ve diğer uygulama türlerinde yerleşik olarak gelir.

Neden kullanılır?

  • Sınıflar birbirine sıkı bağlı olmaz; bir uygulamayı değiştirmek kolaylaşır.
  • Birim testlerinde gerçek servis yerine sahte (mock) servis verilebilir. Bkz. birim testi.
  • Yapılandırma ve nesne yaşam döngüsü tek bir yerden yönetilir.

Temel kullanım

builder.Services.AddScoped<ISiparisServisi, SiparisServisi>();

public class SiparisController(ISiparisServisi servis) : ControllerBase
{
    // servis otomatik olarak enjekte edilir
}

Servis ömürleri

  • Singleton: Uygulama boyunca tek bir örnek. Yapılandırma, önbellek gibi durumsuz veya iş parçacığı güvenli servisler için.
  • Scoped: Her istek (web uygulamalarında her HTTP isteği) için bir örnek. Veritabanı bağlamı (DbContext) gibi servisler için.
  • Transient: Her istendiğinde yeni örnek. Hafif ve durumsuz servisler için.

Keyed services

.NET 8 ile gelen anahtarlı servisler, aynı arayüzün birden fazla uygulamasını bir anahtarla kaydedip seçmeyi sağlar. Örneğin farklı SMS sağlayıcıları için ayrı uygulamalar.

Sık yapılan hatalar

Singleton içinde Scoped servis kullanmak

Singleton bir servis, Scoped bir servisi constructor'dan alırsa o Scoped servis de fiilen singleton gibi yaşar. DbContext gibi servislerde bu ciddi hatalara yol açar. Arka plan servislerinde scope oluşturarak kullanmak gerekir; bkz. BackgroundService.

Service locator kullanımı

Her yerde IServiceProvider üzerinden servis istemek, bağımlılıkları gizler ve test etmeyi zorlaştırır.

Çok fazla bağımlılık

Constructor'ı on parametre alan bir sınıf, muhtemelen çok fazla iş yapıyordur; bölünmesi gerekebilir.

Disposable servisleri elle oluşturmak

DI tarafından yönetilmeyen IDisposable nesnelerin ömrünü takip etmek zorlaşır.

Konsol ve masaüstü uygulamalarında DI

Generic Host (Host.CreateApplicationBuilder) ile konsol, WPF ve WinForms uygulamalarında da aynı DI altyapısı kullanılabilir. Bu, büyüyen masaüstü projelerinde kodu düzenli tutmanın etkili bir yoludur.

Sık sorulan sorular

DI performansı düşürür mü?

Yerleşik DI konteyneri hızlıdır; çoğu uygulamada fark edilir bir etkisi yoktur.

Üçüncü taraf DI konteyneri gerekir mi?

Çoğu proje için yerleşik konteyner yeterlidir. Gelişmiş özellikler gerekiyorsa alternatifler değerlendirilebilir.

Sonuç

Doğru kurulmuş bir DI yapısı, test edilebilir ve bakımı kolay kodun temelidir. Mevcut projelerinizde mimari iyileştirme için destek alabilirsiniz.