在 BackgroundService
内使用作用域服务
当使用任意 AddHostedService 扩展方法注册 IHostedService 的实现时,该服务被注册为单一实例。 在某些情况下,你可能想要依赖于作用域服务。 有关详细信息,请参阅 .NET 服务生存期中的依赖关系注入。
在本教程中,你将了解如何执行以下操作:
- 解析单一实例 BackgroundService 中的作用域依赖关系。
- 将工作委托给作用域服务。
- 实现 BackgroundService.StopAsync(CancellationToken) 的
override
。
提示
所有“.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 辅助角色。
提示
如果使用 Visual Studio Code,则可以从集成终端运行 .NET CLI 命令。 有关详细信息,请参阅 Visual Studio Code:集成终端。
创建作用域服务
要在 BackgroundService
中使用有作用域的服务,请创建一个作用域。 默认情况下,不会为托管服务创建作用域。 作用域后台服务包含后台任务的逻辑。
namespace App.ScopedService;
public interface IScopedProcessingService
{
Task DoWorkAsync(CancellationToken stoppingToken);
}
前面的接口定义了一个 DoWorkAsync
方法。 定义默认实现:
- 服务是异步的。
DoWorkAsync
方法返回Task
。 出于演示目的,在DoWorkAsync
方法中等待 10 秒的延迟。 - ILogger 注入到服务中:
namespace App.ScopedService;
public sealed class DefaultScopedProcessingService(
ILogger<DefaultScopedProcessingService> logger) : IScopedProcessingService
{
private int _executionCount;
public async Task DoWorkAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
++ _executionCount;
logger.LogInformation(
"{ServiceName} working, execution count: {Count}",
nameof(DefaultScopedProcessingService),
_executionCount);
await Task.Delay(10_000, stoppingToken);
}
}
}
托管服务创建一个作用域来解决作用域后台服务以调用其 DoWorkAsync
方法。 DoWorkAsync
返回 ExecuteAsync
等待的 Task
:
重写辅助角色类
将现有 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);
await DoWorkAsync(stoppingToken);
}
private async Task DoWorkAsync(CancellationToken stoppingToken)
{
logger.LogInformation(
"{Name} is working.", ClassName);
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
IScopedProcessingService scopedProcessingService =
scope.ServiceProvider.GetRequiredService<IScopedProcessingService>();
await scopedProcessingService.DoWorkAsync(stoppingToken);
}
}
public override async Task StopAsync(CancellationToken stoppingToken)
{
logger.LogInformation(
"{Name} is stopping.", ClassName);
await base.StopAsync(stoppingToken);
}
}
在前面的代码中,将创建一个显式作用域,并通过依赖关系注入服务范围工厂解析 IScopedProcessingService
实现。 解析后的服务实例是有作用域的,它的 DoWorkAsync
方法正在等待。
将模板 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 run 命令的详细信息,请参阅 dotnet run。
让应用程序运行一段时间,以生成多个执行计数增量。 你将看到与下面类似的输出:
info: App.ScopedService.ScopedBackgroundService[0]
ScopedBackgroundService is running.
info: App.ScopedService.ScopedBackgroundService[0]
ScopedBackgroundService is working.
info: App.ScopedService.DefaultScopedProcessingService[0]
DefaultScopedProcessingService working, execution count: 1
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 working, execution count: 2
info: App.ScopedService.DefaultScopedProcessingService[0]
DefaultScopedProcessingService working, execution count: 3
info: App.ScopedService.DefaultScopedProcessingService[0]
DefaultScopedProcessingService working, execution count: 4
info: Microsoft.Hosting.Lifetime[0]
Application is shutting down...
info: App.ScopedService.ScopedBackgroundService[0]
ScopedBackgroundService is stopping.
如果从 Visual Studio 内部运行应用程序,请选择“调试”>“停止调试...” 。或者,从控制台窗口中选择“Ctrl” + “C”,以发送取消信号。