BackgroundService中使用范围服务

当您注册IHostedService的实现时,无论使用哪种AddHostedService扩展方法,服务都会注册为单例。 在某些情况下,你可能希望依赖作用域服务。 有关详细信息,请参阅 .NET 中的依赖项注入:服务生存期

本教程中,您将学习如何:

小窍门

所有“.NET 中的辅助角色”示例源代码都可以在示例浏览器中下载。 有关详细信息,请参阅浏览代码示例:.NET 中的辅助角色

先决条件

创建新项目

若要使用 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 以发出取消信号。

另请参阅