本文内容
- 先决条件
- 创建新的控制台应用程序
- 添加接口
- 添加默认实现
- 添加需要 DI 的服务
- 为 DI 注册服务
- 结束语
本文介绍如何在 .NET 中使用依赖注入 (DI)。 借助 Microsoft 扩展,可通过添加服务并在IServiceCollection中配置这些服务来管理 DI。IHost接口会公开IServiceProvider实例,它充当所有已注册的服务的容器。
本文介绍如何执行下列操作:
- 创建一个使用依赖注入的 .NET 控制台应用
- 生成和配置通用主机
- 编写多个接口及相应的实现
- 为 DI 使用服务生存期和范围设定
1、先决条件
- .NET Core 3.1 SDK或更高版本。
- 熟悉如何创建新的 .NET 应用程序以及如何安装 NuGet 包。
2、创建新的控制台应用程序
通过dotnet new命令或 IDE 的“新建项目”向导,新建一个名为 ConsoleDI 的 .NET 控制台应用程序Example。 将 NuGet 包Microsoft.Extensions.Hosting添加到项目。
新的控制台应用项目文件应如下所示:
Exe
net7.0
enable
true
ConsoleDI.Example
重要
在此示例中,需要 NuGet 包Microsoft.Extensions.Hosting来生成和运行应用。 某些元包可能包含Microsoft.Extensions.Hosting
包,在这种情况下,不需要显式包引用。
3、添加接口
在此示例应用中,你将了解依赖项注入如何处理服务生存期。 你将创建多个表示不同服务生存期的接口。 将以下接口添加到项目根目录:
IReportServiceLifetime.cs
using Microsoft.Extensions.DependencyInjection;
namespace ConsoleDI.Example;
public interface IReportServiceLifetime
{
Guid Id { get; }
ServiceLifetime Lifetime { get; }
}
IReportServiceLifetime
接口定义了以下项:
- 表示服务的唯一标识符的
Guid Id
属性。 - 表示服务生存期的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
的所有子接口均使用默认值显式实现IReportServiceLifetime.Lifetime
。 例如,IExampleTransientService
使用ServiceLifetime.Transient
值显式实现IReportServiceLifetime.Lifetime
。
4、添加默认实现
该示例实现使用Guid.NewGuid()的结果初始化其Id
属性。 将各种服务的下列默认实现类添加到项目根目录:
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();
}
每个实现都定义为internal sealed
并实现其相应的接口。 例如,ExampleSingletonService
会实现IExampleSingletonService
。
5、添加需要 DI 的服务
添加下列服务生存期报告器类,它作为服务添加到控制台应用:
ServiceLifetimeReporter.cs
namespace ConsoleDI.Example;
internal sealed class ServiceLifetimeReporter
{
private readonly IExampleTransientService _transientService;
private readonly IExampleScopedService _scopedService;
private readonly IExampleSingletonService _singletonService;
public ServiceLifetimeReporter(
IExampleTransientService transien服务器托管网tService,
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 service, string message)
where T : IReportServiceLifetime =>
Console.WriteLine(
$" {typeof(T).Name}: {service.Id} ({message})");
}
ServiceLifetimeReporter
会定义一个构造函数,该函数需要上述每一个服务接口(即IExampleTransientService
、IExampleScopedService
和IExampleSingletonService
)。 对象会公开一个方法,使用者可通过该方法使用给定的lif服务器托管网etimeDetails
参数报告服务。 被调用时,ReportServiceLifetimeDetails
方法会使用服务生存期消息记录每个服务的唯一标识符。 日志消息有助于直观呈现服务生存期。
6、为 DI 注册服务
使用以下代码更新 Program.cs:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using ConsoleDI.Example;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddTransient();
builder.Services.AddScoped();
builder.Services.AddSingleton();
builder.Services.AddTransient();
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();
logger.ReportServiceLifetimeDetails(
$"{lifetime}: Call 1 to provider.GetRequiredService()");
Console.WriteLine("...");
logger = provider.GetRequiredService();
logger.ReportServiceLifetimeDetails(
$"{lifetime}: Call 2 to provider.GetRequiredService()");
Console.WriteLine();
}
每个services.Add{LIFETIME}
扩展方法添加(并可能配置)服务。 我们建议应用遵循此约定。 将扩展方法置于Microsoft.Extensions.DependencyInjection命名空间中以封装服务注册的组。 还包括用于 DI 扩展方法的命名空间部分Microsoft.Extensions.DependencyInjection
:
- 允许在不添加其他
using
块的情况下在IntelliSense中显示它们。 - 在通常会调用这些扩展方法的
Program
或Startup
类中,避免出现过多的using
语句。
应用会执行以下操作:
- 使用默认活页夹设置创建一个IHostBuilder实例。
- 配置服务并对其添加相应的服务生存期。
- 调用Build()并分配IHost的实例。
- 调用
ExemplifyScoping
,传入IHost.Services。
7、结束语
在此示例应用中,你创建了多个接口和相应的实现。 其中每个服务都唯一标识并与ServiceLifetime配对。 示例应用演示了如何针对接口注册服务实现,以及如何在没有支持接口的情况下注册纯类。 然后,示例应用演示了如何在运行时解析定义为构造函数参数的依赖项。
运行该应用时,它会显示如下所示的输出:
// Sample output:
// Lifetime 1: Call 1 to provider.GetRequiredService()
// 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()
// 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()
// 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()
// 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)
在应用输出中,可看到:
- Transient 服务总是不同的,每次检索服务时,都会创建一个新实例。
- Scoped 服务只会随着新范围而改变,但在一个范围中是相同的实例。
- Singleton 服务总是相同的,新实例仅被创建一次。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
目录 1、ICMP的概念 2、ICMP重定向 3、利用ICMP重定向进行攻击的原理 4、如何禁止ICMP重定向功能? 4.1、在Linux系统中禁用 4.2、在Windows系统中禁用 5、关于ICMP重定向的问题实例 VC++常用功能开发汇总(专栏文章列表,…