在
当您注册IHostedService的实现时,无论使用哪种AddHostedService扩展方法,服务都会注册为单例。 在某些情况下,你可能希望依赖作用域服务。 有关详细信息,请参阅 .NET 中的依赖项注入:服务生存期。
本教程中,您将学习如何:
- 正确解析单一实例 BackgroundService中的作用域内依赖项。
- 将工作委托给有范围的服务。
- 实现一个
override
和BackgroundService.StopAsync(CancellationToken)的。
小窍门
所有“.NET 中的辅助角色”示例源代码都可以在示例浏览器中下载。 有关详细信息,请参阅浏览代码示例:.NET 中的辅助角色。
先决条件
- .NET 8.0 SDK 或更高版本
- .NET 集成开发环境 (IDE)
- 随意使用 Visual Studio
创建新项目
若要使用 Visual Studio 创建新的辅助角色服务项目,请选择“ 文件>新建>项目...”。从“ 创建新项目 ”对话框搜索“辅助角色服务”,然后选择“辅助角色服务”模板。 如果想要使用 .NET CLI,请在工作目录中打开你喜欢的终端。 运行dotnet new
命令,并将<Project.Name>
替换为您所需的项目名称。
dotnet new worker --name <Project.Name>
有关 .NET CLI 新辅助角色服务项目命令的详细信息,请参阅 dotnet new worker。
小窍门
如果使用 Visual Studio Code,可以从集成终端运行 .NET CLI 命令。 有关详细信息,请参阅 Visual Studio Code:集成终端。
创建作用域内服务
若要在某个BackgroundService
范围内使用作用域服务,请使用 IServiceScopeFactory.CreateScope() API 创建范围。 默认情况下,不会为托管服务创建作用域。 作用域内后台服务包含后台任务的逻辑。
namespace App.ScopedService;
public interface IScopedProcessingService
{
Task DoWorkAsync(CancellationToken stoppingToken);
}
前面的接口定义单个 DoWorkAsync
方法。 在名为 DefaultScopedProcessingService.cs 的新类中创建实现:
namespace App.ScopedService;
public sealed class DefaultScopedProcessingService(
ILogger<DefaultScopedProcessingService> logger) : IScopedProcessingService
{
private readonly string _instanceId = Guid.NewGuid().ToString();
public Task DoWorkAsync(CancellationToken stoppingToken)
{
logger.LogInformation(
"{ServiceName} doing work, instance ID: {Id}",
nameof(DefaultScopedProcessingService),
_instanceId);
return Task.CompletedTask;
}
}
- 使用主构造函数将 ILogger 注入到服务中。
- 该
DoWorkAsync
方法返回Task
并接受CancellationToken。- 该方法记录实例标识符 —— 在类实例化时会分配
_instanceId
。
- 该方法记录实例标识符 —— 在类实例化时会分配
重写 Worker 类
将现有 Worker
类替换为以下 C# 代码,并将文件重命名为 ScopedBackgroundService.cs:
namespace App.ScopedService;
public sealed class ScopedBackgroundService(
IServiceScopeFactory serviceScopeFactory,
ILogger<ScopedBackgroundService> logger) : BackgroundService
{
private const string ClassName = nameof(ScopedBackgroundService);
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
logger.LogInformation(
"{Name} is running.", ClassName);
while (!stoppingToken.IsCancellationRequested)
{
using IServiceScope scope = serviceScopeFactory.CreateScope();
IScopedProcessingService scopedProcessingService =
scope.ServiceProvider.GetRequiredService<IScopedProcessingService>();
await scopedProcessingService.DoWorkAsync(stoppingToken);
await Task.Delay(10_000, stoppingToken);
}
}
public override async Task StopAsync(CancellationToken stoppingToken)
{
logger.LogInformation(
"{Name} is stopping.", ClassName);
await base.StopAsync(stoppingToken);
}
}
在前面的代码中,虽然 stoppingToken
未取消,但 IServiceScopeFactory
用于创建范围。 从IServiceScope
中解析出IScopedProcessingService
。 该方法DoWorkAsync
正在等待中,并将stoppingToken
传递给此方法。 最后,执行延迟 10 秒,循环继续。 每次调用该方法时 DoWorkAsync
,都会创建一个新实例 DefaultScopedProcessingService
并记录实例标识符。
将模板 Program.cs 文件内容替换为以下 C# 代码:
using App.ScopedService;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<ScopedBackgroundService>();
builder.Services.AddScoped<IScopedProcessingService, DefaultScopedProcessingService>();
IHost host = builder.Build();
host.Run();
服务注册在 (Program.cs) 中。 托管服务使用 AddHostedService 扩展方法进行注册。
有关注册服务的详细信息,请参阅 .NET 中的依赖关系注入。
验证服务功能
若要从 Visual Studio 运行应用程序,请选择 F5 或选择 “调试>开始调试 ”菜单选项。 如果使用 .NET CLI,请从工作目录中运行以下命令 dotnet run
:
dotnet run
有关 .NET CLI 运行命令的详细信息,请参阅 dotnet run。
让应用程序运行一会儿,以生成多个对DoWorkAsync
的调用,从而记录新的实例标识符。 会看到类似于以下日志的输出:
info: App.ScopedService.ScopedBackgroundService[0]
ScopedBackgroundService is running.
info: App.ScopedService.DefaultScopedProcessingService[0]
DefaultScopedProcessingService doing work, instance ID: 8986a86f-b444-4139-b9ea-587daae4a6dd
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: .\scoped-service
info: App.ScopedService.DefaultScopedProcessingService[0]
DefaultScopedProcessingService doing work, instance ID: 07a4a760-8e5a-4c0a-9e73-fcb2f93157d3
info: App.ScopedService.DefaultScopedProcessingService[0]
DefaultScopedProcessingService doing work, instance ID: c847f432-acca-47ee-8720-1030859ce354
info: Microsoft.Hosting.Lifetime[0]
Application is shutting down...
info: App.ScopedService.ScopedBackgroundService[0]
ScopedBackgroundService is stopping.
如果从 Visual Studio 中运行应用程序,请选择 “调试>停止调试...”。或者,从控制台窗口中选择 Ctrl + C 以发出取消信号。
另请参阅
- .NET 中的工作者服务
- 创建队列服务
使用 创建 Windows 服务 -
实现
IHostedService
接口