本文內(nèi)容
- 先決條件
- 創(chuàng)建新的控制臺應(yīng)用程序
- 添加接口
- 添加默認(rèn)實現(xiàn)
- 添加需要 DI 的服務(wù)
- 為 DI 注冊服務(wù)
- 結(jié)束語
本文介紹如何在 .NET 中使用依賴注入 (DI)。 借助 Microsoft 擴展,可通過添加服務(wù)并在?IServiceCollection?中配置這些服務(wù)來管理 DI。?IHost?接口會公開?IServiceProvider?實例,它充當(dāng)所有已注冊的服務(wù)的容器。
本文介紹如何執(zhí)行下列操作:
- 創(chuàng)建一個使用依賴注入的 .NET 控制臺應(yīng)用
- 生成和配置通用主機
- 編寫多個接口及相應(yīng)的實現(xiàn)
- 為 DI 使用服務(wù)生存期和范圍設(shè)定
1、先決條件
- .NET Core 3.1 SDK?或更高版本。
- 熟悉如何創(chuàng)建新的 .NET 應(yīng)用程序以及如何安裝 NuGet 包。
2、創(chuàng)建新的控制臺應(yīng)用程序
通過?dotnet new?命令或 IDE 的“新建項目”向?qū)В陆ㄒ粋€名為 ConsoleDI 的 .NET 控制臺應(yīng)用程序?Example?。 將 NuGet 包?Microsoft.Extensions.Hosting?添加到項目。
新的控制臺應(yīng)用項目文件應(yīng)如下所示:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<RootNamespace>ConsoleDI.Example</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
</ItemGroup>
</Project>
?重要
在此示例中,需要 NuGet 包?Microsoft.Extensions.Hosting?來生成和運行應(yīng)用。 某些元包可能包含?Microsoft.Extensions.Hosting
?包,在這種情況下,不需要顯式包引用。
3、添加接口
在此示例應(yīng)用中,你將了解依賴項注入如何處理服務(wù)生存期。 你將創(chuàng)建多個表示不同服務(wù)生存期的接口。 將以下接口添加到項目根目錄:
IReportServiceLifetime.cs
using Microsoft.Extensions.DependencyInjection;
namespace ConsoleDI.Example;
public interface IReportServiceLifetime
{
Guid Id { get; }
ServiceLifetime Lifetime { get; }
}
IReportServiceLifetime
?接口定義了以下項:
- 表示服務(wù)的唯一標(biāo)識符的?
Guid Id
?屬性。 - 表示服務(wù)生存期的?ServiceLifetime?屬性。
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
?的所有子接口均使用默認(rèn)值顯式實現(xiàn)?IReportServiceLifetime.Lifetime
。 例如,IExampleTransientService
?使用?ServiceLifetime.Transient
?值顯式實現(xiàn)?IReportServiceLifetime.Lifetime
。
4、添加默認(rèn)實現(xiàn)
該示例實現(xiàn)使用?Guid.NewGuid()?的結(jié)果初始化其?Id
?屬性。 將各種服務(wù)的下列默認(rèn)實現(xiàn)類添加到項目根目錄:
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();
}
每個實現(xiàn)都定義為?internal sealed
?并實現(xiàn)其相應(yīng)的接口。 例如,ExampleSingletonService
?會實現(xiàn)?IExampleSingletonService
。
5、添加需要 DI 的服務(wù)
添加下列服務(wù)生存期報告器類,它作為服務(wù)添加到控制臺應(yīng)用:
ServiceLifetimeReporter.cs
namespace ConsoleDI.Example;
internal sealed class ServiceLifetimeReporter
{
private readonly IExampleTransientService _transientService;
private readonly IExampleScopedService _scopedService;
private readonly IExampleSingletonService _singletonService;
public ServiceLifetimeReporter(
IExampleTransientService transientService,
IExampleScopedService scopedService,
IExampleSingletonService singletonService) =>
(_transientService, _scopedService, _singletonService) =
(transientService, scopedService, 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
?會定義一個構(gòu)造函數(shù),該函數(shù)需要上述每一個服務(wù)接口(即?IExampleTransientService
、IExampleScopedService
?和?IExampleSingletonService
)。 對象會公開一個方法,使用者可通過該方法使用給定的?lifetimeDetails
?參數(shù)報告服務(wù)。 被調(diào)用時,ReportServiceLifetimeDetails
?方法會使用服務(wù)生存期消息記錄每個服務(wù)的唯一標(biāo)識符。 日志消息有助于直觀呈現(xiàn)服務(wù)生存期。
6、為 DI 注冊服務(wù)
使用以下代碼更新 Program.cs:
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();
}
每個?services.Add{LIFETIME}<{SERVICE}>
?擴展方法添加(并可能配置)服務(wù)。 我們建議應(yīng)用遵循此約定。 將擴展方法置于?Microsoft.Extensions.DependencyInjection?命名空間中以封裝服務(wù)注冊的組。 還包括用于 DI 擴展方法的命名空間部分?Microsoft.Extensions.DependencyInjection
:
- 允許在不添加其他?
using
?塊的情況下在?IntelliSense?中顯示它們。 - 在通常會調(diào)用這些擴展方法的?
Program
?或?Startup
?類中,避免出現(xiàn)過多的?using
?語句。
應(yīng)用會執(zhí)行以下操作:
- 使用默認(rèn)活頁夾設(shè)置創(chuàng)建一個?IHostBuilder?實例。
- 配置服務(wù)并對其添加相應(yīng)的服務(wù)生存期。
- 調(diào)用?Build()?并分配?IHost?的實例。
- 調(diào)用?
ExemplifyScoping
,傳入?IHost.Services。
7、結(jié)束語
在此示例應(yīng)用中,你創(chuàng)建了多個接口和相應(yīng)的實現(xiàn)。 其中每個服務(wù)都唯一標(biāo)識并與?ServiceLifetime?配對。 示例應(yīng)用演示了如何針對接口注冊服務(wù)實現(xiàn),以及如何在沒有支持接口的情況下注冊純類。 然后,示例應(yīng)用演示了如何在運行時解析定義為構(gòu)造函數(shù)參數(shù)的依賴項。
運行該應(yīng)用時,它會顯示如下所示的輸出:文章來源:http://www.zghlxwxcb.cn/news/detail-758232.html
// 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)
在應(yīng)用輸出中,可看到:文章來源地址http://www.zghlxwxcb.cn/news/detail-758232.html
- Transient 服務(wù)總是不同的,每次檢索服務(wù)時,都會創(chuàng)建一個新實例。
- Scoped 服務(wù)只會隨著新范圍而改變,但在一個范圍中是相同的實例。
- Singleton 服務(wù)總是相同的,新實例僅被創(chuàng)建一次。
到了這里,關(guān)于【微軟技術(shù)?!緾#.NET 中使用依賴注入的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!