Bu yazıda .NET 8 ile gelen ve Keyed Services özelliğinden bahsedilecektir.
Dependency Injection (DI) yapısını hatırlamak gerekirse;
Dependency Injection, projelerimizde bulunan bağımlılıkların yönetebildiği, nesneleri bağımlılıktan kurtaran, değişiklik gerektiğinde minimum değişiklikle düzenleme yapılabilen bir prensiptir.
Temel yaşam süreleri ise;
Singleton, Scoped, Transient
Konu ile ilgili ".NET Core - Dependency Injection - Oluşturulan Nesnelerin Yaşam Sürelerini Anlamak" başlıklı yazımda detaylarını bahsetmiştim.
Bugünkü yazıda yaşam sürelerine değil; .NET Core'den beri hayatımızda bulunan Dependency Injection yapısına .NET 8 ile gelen bir özellik olan Keyed Services özelliğine odaklanılacaktır.
Bağlılıkları isimlendirmek ve aynı servis ismiyle birden fazla key tanımlayarak farklı yerlerde enjekte edilmesi sağlanacaktır.
.NET 8 Öncesi Yaşam Sürelerinin Yönetilmesi
Deneyimlediğim iki farklı yolu bulunuyor.
İlk seçenek, yaşam süreleri belirlenen bütün servislerden kodun akış sırasına göre en son tanımlanan çalışırdı.
|
Program.cs'de tanımlanan yaşam süreleri |
|
Controller sınıfında DI kullanımı |
Bu görselde SophomoreService en son tanımlandığından, controllerda enjekte edilen de SophomoreService gelecektir. Bu şekilde de sadece tek bir servis kullanılır.
|
SophomoreService |
Loglarda hem FromServices attributesi hem de constructor enjektasyonundan tanımlandığı için Output ekranından log yazılmış oldu. Buradan da SophomoreService sınıfından çağrıldığı belli olmaktadır.
|
ILogger mesajı |
Diğer seçenek, yaşam döngüleriyle ayarlanmış IStudentService ile oluşturulmuş bütün servislerin liste halinde controller constructor metodunda ayarlanarak kullanmak istenilen servisi bulunmasıdır. Listede filtrelemek de ek bir iş olacaktır.
|
IStudentService türünden listede görünen servisler |
Yeni Özellikte Neler Var?
Yeni gelen Keyed servislerle, kullanmak istenilen servisi anahtar bir kelime ile isimlendirdikten sonra, enjekte etmek istenilen yerden bu isimle çağrılabilir.
String bir isimlendirme yapabileceğiniz gibi enum yapıları da kullanabilir. Bu makalede, daha temiz kod anlayışı ile enum yöntemini tercih edeceğim.
Program.cs dosyasından servislerin yaşam döngüleri, aşağıdaki tabloda karşılaştırılmıştır.
Mevcut Yaşam Döngüleri ve Keyed DI karşılığı
|
|
.NET 8 Öncesi |
KeyedDI Karşılığı |
Singleton |
services.AddSingleton<TService, TImplementation>() |
services.AddKeyedSingleton<TService, TImplementation>(object key)
|
|
Transient |
services.AddTransient<TService, TImplementation>() | services.AddKeyedTransient<TService, TImplementation>(object key)
|
|
Scoped |
services.AddScoped<TService, TImplementation>() |
services.AddKeyedScoped<TService, TImplementation>(object key)
|
|
Örnek Uygulama Hakkında
Örnek bir uygulamada öğrenci tipleri ile ilgili işlemleri yapan sınıflar var. Daha temiz bir key vererek isimlendirme yapmak için StudentType enum yapısı oluşturuldu. Enumdaki her değer, öğrenci tipine karşılık gelmektedir.
|
StudentType enum
|
Program.cs sınıfında AddKeyedTransient olarak uygulamada enjekte edilmek üzere ayarlandı. nameof ile enumların ismi key olarak verildi. (JuniorService için key ismi Junior olacaktır.)
|
AddKeyedTransient kullanımı
|
IStudentService interfacesi ise GetStudentId propertysini tutsun. Diğer öğrenci tipleri bu interface'yi miras alacaktır.
|
IStudentService |
SeniorService.cs constructor ile loglama işlemi yapacaktır. Output ekranında yazmasını istiyoruz. Ayrıca tekil bir id değeri de yaratacaktır.
|
SeniorService.cs |
JuniorService, SpecialStudentService, SophomoreService, FreshmanService sınıfları da diğer öğrenci tipleridir.
Servislerin Kullanılması
.NET ekosisteminde IServiceProvider interfacesi ile Dependency Injection yönetimi yapılmakta ve yaşam döngülerini kullanarak oluşturulan servislere buradan ulaşılır. Listede, AddKeyedServices ile eklenen ve isimleri bulunan servisler aşağıdaki gibi görünmektedir.
|
Keyed Servislerin Provider ile görünmesi |
GetKeyedService vs GetRequiredKeyedService
Bu iki metot, provider'de bulunan key ile servisin kullanılmasını sağlar. Parametre olarak key ismi StudentType enum değeri ile verildi.
Aralarındaki en önemli fark, GetKeyedService'deki isme sahip bir implementasyon yoksa değeri null olabilecekken, GetRequiredKeyedService metodundan ise InvalidOperationException hatası fırlatacaktır.
Yukarıdaki görseldeki hata ise uygulamada "Freshman" keyi ile bir servis tanımlamamış olmamızdan kaynaklıdır. GetRequiredKeyedService, diğerine göre daha katı bir metottur.
FromKeyedServices Attribute
Metodun parametresinde kullanabileceğimiz bir attribute nesnesidir. Key ismi vererek ilgili servis kullanılabilir. Parametre olarak verilen keyed servisinin Program.cs dosyasında tanımlı olması gerekir.
Loglarda da bu metot çağrıldığında enjekte edilmiş servisler görünmektedir.
Özetle;
İki versiyon arasında DependencyInjection yapısı kullanım farklarını ve KeyedService özelliğinin uygulanışına değindik.
Yazı boyunca değindiğim bu özelliğin proje geliştirme aşamasında hayat kurtarabilecek bir özellik olduğuna inanıyorum.
Uygulamanın örnek projesine Github Linkinden ulaşılabilirsiniz. Yazının faydalı olmasını umarak çalışmalarınızda kolaylıklar diliyorum :)
Yararlanılan Kaynaklar
Yorumlar
Yorum Gönder