Yazılım ve Teknoloji

NET’te Dependency Injection: Temellerden İleri Seviye Kullanıma

27 Okunma 29.09.2025
NET’te Dependency Injection: Temellerden İleri Seviye Kullanıma

Yazılım projeleri büyüdükçe sınıflar arasındaki bağımlılıklar da artar. Bir sınıfın, ihtiyaç duyduğu nesneyi kendi içinde oluşturması ilk bakışta pratik görünebilir. Ancak bu yaklaşım, uzun vadede test edilebilirliği zorlaştırır, esnekliği azaltır ve değişiklik maliyetlerini yükseltir.


İşte tam bu noktada Dependency Injection (DI) devreye girer. Türkçesiyle “bağımlılık enjeksiyonu”, sınıfların ihtiyaç duyduğu nesneleri kendilerinin üretmesi yerine, bu nesnelerin dışarıdan sağlanması prensibine dayanır.


Dependency Injection’un Temel Mantığı

DI’nin en büyük amacı, kodu bağımlılıklardan kurtararak esnek, tekrar kullanılabilir ve kolay test edilebilir hale getirmektir.

Örneğin bir ödeme servisi düşünelim. Eğer bu servis doğrudan kredi kartı işlemcisine bağlıysa, yarın başka bir ödeme sağlayıcısına geçmek istediğinizde tüm kodu değiştirmeniz gerekir. Oysa DI ile ödeme servisi, yalnızca bir arayüze bağımlı olur. Bu sayede kredi kartı, PayPal ya da başka bir servis kolayca entegre edilebilir.


.NET Core’da Yerleşik DI Container

Eskiden .NET projelerinde bağımlılık yönetimi için genellikle Autofac, Ninject gibi üçüncü parti kütüphaneler kullanılırdı. Ancak .NET Core ile birlikte artık yerleşik bir DI Container bulunuyor.

Bu container sayesinde bağımlılıkların ömürleri belirlenebiliyor:

  • Transient: Her talep için yeni bir nesne üretilir.
  • Scoped: Web uygulamalarında her istek (request) için tek bir nesne oluşturulur.
  • Singleton: Uygulama boyunca tek bir nesne paylaşılır.

Bu üç yaklaşım, servislerin kullanım amacına göre seçilerek bellek yönetimi ve performans açısından en uygun çözümün sağlanmasına yardımcı olur.


Factory Pattern ile DI

Bazı bağımlılıkların oluşturulması özel bir mantık gerektirir. Örneğin e-posta servisini konfigürasyona göre farklı ayarlarda çalıştırmak isteyebilirsiniz. Bu durumda fabrikasyon mantığıyla, servisin nasıl oluşturulacağını DI container’a tarif edebilirsiniz.


Generic Servis Kayıtları

Birçok projede tekrar eden repository ya da servis yapıları olur. DI sayesinde generic bir yapı tanımlayarak, tüm entity’ler için aynı repository mantığını kolayca uygulayabilirsiniz.


Birden Fazla Implementasyon

Bazen aynı arayüzün birden fazla farklı implementasyonu bulunur. Örneğin bir SMS servisi hem Twilio hem de Nexmo üzerinden çalışabilir. DI sayesinde bu implementasyonlar tanımlanır, hangi durumda hangisinin kullanılacağı ise ayrı bir mantıkla (örneğin Strategy Pattern) belirlenebilir.


Ortam Bazlı Bağımlılıklar

Uygulamanız geliştirme, test ve üretim ortamlarında farklı servisler kullanabilir. Örneğin geliştirme ortamında sahte bir ödeme servisi, üretimde ise gerçek ödeme sağlayıcısı kullanılabilir. DI container, ortam bilgisine göre hangi implementasyonun devreye alınacağını kolayca yönetebilir.


Middleware Entegrasyonu

ASP.NET Core’un en güçlü yanlarından biri olan middleware yapıları da DI ile uyumlu çalışır. Örneğin bir logging middleware bileşeni, DI sayesinde logger servisini doğrudan kullanabilir. Bu sayede isteklerin başlama ve bitiş zamanları merkezi olarak kaydedilebilir.


Test Edilebilirlik

DI’nin en önemli faydalarından biri, test süreçlerindeki kolaylıktır. Çünkü bir sınıf gerçek bağımlılık yerine, sahte (mock) nesnelerle test edilebilir hale gelir. Bu sayede veritabanı ya da harici servisleri kullanmadan, yalnızca ilgili sınıfın iş mantığı kontrol edilebilir.


Clean Architecture ve Dependency Injection

Dependency Injection, Clean Architecture, Onion Architecture ya da Domain Driven Design gibi modern mimarilerde kritik rol oynar.

  • Uygulamanın iş mantığı yalnızca arayüzlere bağımlıdır.
  • Gerçek implementasyonlar altyapı katmanında bulunur.
  • DI Container, uygulama çalıştırıldığında hangi arayüzün hangi sınıfla eşleşeceğini belirler.

Böylece uygulama daha modüler, yönetilebilir ve değişime açık hale gelir.


Performans ve Dikkat Edilmesi Gerekenler

  • Gereksiz Singleton kullanımı bellek tüketimini artırabilir.
  • Çok sık kullanılan, ağır bağımlılıkları Transient tanımlamak performans sorunlarına yol açabilir.
  • Constructor Injection tercih edilmelidir, çünkü servis sağlayıcıyı doğrudan çağırmak bağımlılık yönetimini zorlaştırır.
  • Circular dependency (iki sınıfın birbirine bağımlı hale gelmesi) hatasından kaçınılmalıdır.


Sonuç

Dependency Injection, modern .NET projelerinin olmazsa olmazıdır. Hem küçük ölçekli hem de kurumsal projelerde esnekliği, test edilebilirliği ve bakım kolaylığını artırır.

  • Temel seviyede bağımlılıkları constructor üzerinden ayırarak başlayabilirsiniz.
  • İleri seviyede generic servisler, ortam bazlı konfigürasyonlar, factory pattern ve middleware entegrasyonu ile esnekliği artırabilirsiniz.
  • Clean Architecture ile birlikte kullanıldığında projeleriniz uzun vadede çok daha sürdürülebilir bir hale gelir.