.NET'te bağımlılık enjeksiyonu kullanma öğreticisi
Bu öğreticide .NET'da
Bu öğreticide şunların nasıl yapılacağını öğreneceksiniz:
- Bağımlılık ekleme kullanan bir .NET konsol uygulaması oluşturma
- Genel Ana Bilgisayar oluştur ve yapılandır
- Çeşitli arabirimler ve karşılık gelen uygulamalar yazma
- DI için hizmet ömrünü ve kapsam belirlemeyi kullanma
Önkoşullar
- .NET Core 3.1 SDK ya da daha sonraki bir sürüm.
- Yeni .NET uygulamaları oluşturma ve NuGet paketlerini yükleme hakkında bilgi.
Yeni konsol uygulaması oluşturma
dotnet new komutunu veya IDE yeni proje sihirbazını kullanarak ConsoleDI adlı yeni bir .NET konsol uygulaması oluşturun.Example. Projeye Microsoft.Extensions.Hosting NuGet paketini ekleyin.
Yeni konsol uygulaması proje dosyanız aşağıdakine benzer olmalıdır:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<RootNamespace>ConsoleDI.Example</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.3" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.3" />
</ItemGroup>
</Project>
Önemli
Bu örnekte, uygulamayı derlemek ve çalıştırmak için Microsoft.Extensions.Hosting NuGet paketi gereklidir. Bazı meta paketler Microsoft.Extensions.Hosting
paketini içerebilir ve bu durumda açık bir paket başvurusu gerekmez.
Arabirim ekleme
Bu örnek uygulamada bağımlılık eklemenin hizmet ömrünü nasıl işlediğini öğreneceksiniz. Farklı hizmet ömürlerini temsil eden çeşitli arabirimler oluşturacaksınız. Proje kök dizinine aşağıdaki arabirimleri ekleyin:
IReportServiceLifetime.cs
using Microsoft.Extensions.DependencyInjection;
namespace ConsoleDI.Example;
public interface IReportServiceLifetime
{
Guid Id { get; }
ServiceLifetime Lifetime { get; }
}
IReportServiceLifetime
arabirimi aşağıdakileri tanımlar:
- Hizmetin benzersiz tanımlayıcısını temsil eden bir
Guid Id
özelliği. - Hizmet ömrünü temsil eden bir ServiceLifetime özelliği.
IExampleTransientService.cs
using Microsoft.Extensions.DependencyInjection;
namespace ConsoleDI.Example;
public interface IExampleTransientService : IReportServiceLifetime
{
ServiceLifetime IReportServiceLifetime.Lifetime => ServiceLifetime.Transient;
}
IExampleScopedService.cs
using Microsoft.Extensions.DependencyInjection;
namespace ConsoleDI.Example;
public interface IExampleScopedService : IReportServiceLifetime
{
ServiceLifetime IReportServiceLifetime.Lifetime => ServiceLifetime.Scoped;
}
IExampleSingletonService.cs
using Microsoft.Extensions.DependencyInjection;
namespace ConsoleDI.Example;
public interface IExampleSingletonService : IReportServiceLifetime
{
ServiceLifetime IReportServiceLifetime.Lifetime => ServiceLifetime.Singleton;
}
IReportServiceLifetime
'ın tüm alt arabirimleri, varsayılan bir değerle birlikte IReportServiceLifetime.Lifetime
'i açıkça uygular. Örneğin, IExampleTransientService
, IReportServiceLifetime.Lifetime
'i ServiceLifetime.Transient
değeriyle açıkça uygular.
Varsayılan uygulamaları ekleme
Örnek uygulamaların tümü Id
özelliğini Guid.NewGuid()sonucuyla başlatır. Çeşitli hizmetler için aşağıdaki varsayılan uygulama sınıflarını proje kök dizinine ekleyin:
ExampleTransientService.cs
namespace ConsoleDI.Example;
internal sealed class ExampleTransientService : IExampleTransientService
{
Guid IReportServiceLifetime.Id { get; } = Guid.NewGuid();
}
ExampleScopedService.cs
namespace ConsoleDI.Example;
internal sealed class ExampleScopedService : IExampleScopedService
{
Guid IReportServiceLifetime.Id { get; } = Guid.NewGuid();
}
ExampleSingletonService.cs
namespace ConsoleDI.Example;
internal sealed class ExampleSingletonService : IExampleSingletonService
{
Guid IReportServiceLifetime.Id { get; } = Guid.NewGuid();
}
Her uygulama internal sealed
olarak tanımlanır ve ilgili arabirimini uygular. Bunların internal
veya sealed
olması gerekmez, ancak uygulama türlerinin dış tüketicilere sızmasını önlemek için uygulamaları internal
olarak ele almak yaygın bir durum değildir. Ayrıca, her bir tür genişletilmeyeceği için sealed
olarak işaretlenir. Örneğin, ExampleSingletonService
IExampleSingletonService
uygular.
DI gerektiren bir hizmet ekleme
Konsol uygulamasına hizmet işlevi gören aşağıdaki hizmet ömrü muhabir sınıfını ekleyin:
ServiceLifetimeReporter.cs
namespace ConsoleDI.Example;
internal sealed class ServiceLifetimeReporter(
IExampleTransientService transientService,
IExampleScopedService scopedService,
IExampleSingletonService singletonService)
{
public void ReportServiceLifetimeDetails(string lifetimeDetails)
{
Console.WriteLine(lifetimeDetails);
LogService(transientService, "Always different");
LogService(scopedService, "Changes only with lifetime");
LogService(singletonService, "Always the same");
}
private static void LogService<T>(T service, string message)
where T : IReportServiceLifetime =>
Console.WriteLine(
$" {typeof(T).Name}: {service.Id} ({message})");
}
ServiceLifetimeReporter
, yukarıda belirtilen hizmet arabirimlerinin her birini (IExampleTransientService
, IExampleScopedService
ve IExampleSingletonService
) gerektiren bir oluşturucu tanımlar. nesnesi, tüketicinin belirli bir lifetimeDetails
parametresiyle hizmette raporlama yapmasına olanak tanıyan tek bir yöntemi kullanıma sunar. Çağrıldığında, ReportServiceLifetimeDetails
yöntemi, her hizmetin benzersiz tanımlayıcısını ve hizmet ömrü iletisini günlüğe kaydeder. Günlük iletileri hizmet ömrünü görselleştirmeye yardımcı olur.
DI için hizmetleri kaydetme
Program.cs aşağıdaki kodla güncelleştirin:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using ConsoleDI.Example;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddTransient<IExampleTransientService, ExampleTransientService>();
builder.Services.AddScoped<IExampleScopedService, ExampleScopedService>();
builder.Services.AddSingleton<IExampleSingletonService, ExampleSingletonService>();
builder.Services.AddTransient<ServiceLifetimeReporter>();
using IHost host = builder.Build();
ExemplifyServiceLifetime(host.Services, "Lifetime 1");
ExemplifyServiceLifetime(host.Services, "Lifetime 2");
await host.RunAsync();
static void ExemplifyServiceLifetime(IServiceProvider hostProvider, string lifetime)
{
using IServiceScope serviceScope = hostProvider.CreateScope();
IServiceProvider provider = serviceScope.ServiceProvider;
ServiceLifetimeReporter logger = provider.GetRequiredService<ServiceLifetimeReporter>();
logger.ReportServiceLifetimeDetails(
$"{lifetime}: Call 1 to provider.GetRequiredService<ServiceLifetimeReporter>()");
Console.WriteLine("...");
logger = provider.GetRequiredService<ServiceLifetimeReporter>();
logger.ReportServiceLifetimeDetails(
$"{lifetime}: Call 2 to provider.GetRequiredService<ServiceLifetimeReporter>()");
Console.WriteLine();
}
Her bir services.Add{LIFETIME}<{SERVICE}>
uzantısı yöntemi, hizmetleri ekler ve potansiyel olarak yapılandırır. Uygulamaların bu kuralı izlemesini öneririz. Resmi bir Microsoft paketi yazmadığınız sürece uzantı yöntemlerini Microsoft.Extensions.DependencyInjection ad alanına yerleştirmeyin.
Microsoft.Extensions.DependencyInjection
ad alanında tanımlanan uzantı yöntemleri:
-
IntelliSense içinde, ek
using
yönergeler gerektirmeksizin görüntülenir. - Bu uzantı yöntemlerinin genellikle çağrıldığı
using
veyaProgram
sınıflarındaki gerekliStartup
yönergelerinin sayısını azaltın.
Uygulama:
- IHostBuilder örneği, host oluşturucu ayarlarıyla oluşturur.
- Hizmetleri yapılandırır ve bunları ilgili hizmet yaşam döngüsüyle ekler.
- Build() çağırır ve bir IHost örneği atar.
-
ExemplifyScoping
fonksiyonunu IHost.Services'i geçirerek çağırır.
Sonuç
Bu örnek uygulamada, çeşitli arabirimler ve buna karşılık gelen uygulamalar oluşturdunuz. Bu hizmetlerin her biri benzersiz olarak tanımlanır ve bir ServiceLifetimeile eşleştirilir. Örnek uygulama, hizmet uygulamalarını bir arabirime kaydetmeyi ve arabirimleri yedeklemeden saf sınıfları kaydetmeyi gösterir. Örnek uygulama daha sonra oluşturucu parametreleri olarak tanımlanan bağımlılıkların çalışma zamanında nasıl çözüldüğünü gösterir.
Uygulamayı çalıştırdığınızda, aşağıdakine benzer bir çıkış görüntüler:
// Sample output:
// Lifetime 1: Call 1 to provider.GetRequiredService<ServiceLifetimeReporter>()
// IExampleTransientService: d08a27fa-87d2-4a06-98d7-2773af886125 (Always different)
// IExampleScopedService: 402c83c9-b4ed-4be1-b78c-86be1b1d908d (Changes only with lifetime)
// IExampleSingletonService: a61f1ff4-0b14-4508-bd41-21d852484a7b (Always the same)
// ...
// Lifetime 1: Call 2 to provider.GetRequiredService<ServiceLifetimeReporter>()
// IExampleTransientService: b43d68fb-2c7b-4a9b-8f02-fc507c164326 (Always different)
// IExampleScopedService: 402c83c9-b4ed-4be1-b78c-86be1b1d908d (Changes only with lifetime)
// IExampleSingletonService: a61f1ff4-0b14-4508-bd41-21d852484a7b (Always the same)
//
// Lifetime 2: Call 1 to provider.GetRequiredService<ServiceLifetimeReporter>()
// IExampleTransientService: f3856b59-ab3f-4bbd-876f-7bab0013d392 (Always different)
// IExampleScopedService: bba80089-1157-4041-936d-e96d81dd9d1c (Changes only with lifetime)
// IExampleSingletonService: a61f1ff4-0b14-4508-bd41-21d852484a7b (Always the same)
// ...
// Lifetime 2: Call 2 to provider.GetRequiredService<ServiceLifetimeReporter>()
// IExampleTransientService: a8015c6a-08cd-4799-9ec3-2f2af9cbbfd2 (Always different)
// IExampleScopedService: bba80089-1157-4041-936d-e96d81dd9d1c (Changes only with lifetime)
// IExampleSingletonService: a61f1ff4-0b14-4508-bd41-21d852484a7b (Always the same)
Uygulama çıkışında şunları görebilirsiniz:
- Transient hizmetler her zaman farklıdır; her hizmet alımında yeni bir örnek oluşturulur.
- Scoped hizmetler yalnızca yeni bir kapsamla değişiklik gösterir, ancak kapsam içinde aynı örnek olarak kalır.
- Singleton hizmetler her zaman aynıdır, yeni bir örnek yalnızca bir kez oluşturulur.
Ayrıca bkz.
- Bağımlılık enjeksiyonu yönergeleri
- .NET'de bağımlılık eklemeyle ilgili temel bilgileri anlama
- ASP.NET Core'da
Bağımlılık Enjeksiyonu