.NET Core 中的多个后台服务

Har*_*ala 1 c# background-service asp.net-core asp.net-core-hosted-services .net-6.0

在 .NET 6 中创建多个后台任务,这些任务在功能方面彼此独立,并根据计划的时间并行/同时运行。使用 Worker 类模板,我能够创建多个托管/后台服务,并且它们按预期运行。

services.AddHostedService<Worker>();将被视为 Singleton 类,我们需要解决作用域依赖关系,以使服务具有作用域,遵循作用域服务文档中的相同内容。根据上面链接中的示例,示例代码如下所示,作用域服务的接口

  namespace App.ScopedService;
public interface IScopedProcessingService
{
    Task DoWorkAsync(CancellationToken stoppingToken);
} 
Run Code Online (Sandbox Code Playgroud)

以及接口的默认实现

namespace App.ScopedService;

public class DefaultScopedProcessingService : IScopedProcessingService
{
    private int _executionCount;
    private readonly ILogger<DefaultScopedProcessingService> _logger;

    public DefaultScopedProcessingService(
        ILogger<DefaultScopedProcessingService> logger) =>
        _logger = logger;

    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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是后台服务实现

namespace App.ScopedService;

public sealed class ScopedBackgroundService : BackgroundService
{
    private readonly IServiceProvider _serviceProvider;
    private readonly ILogger<ScopedBackgroundService> _logger;

    public ScopedBackgroundService(
        IServiceProvider serviceProvider,
        ILogger<ScopedBackgroundService> logger) =>
        (_serviceProvider, _logger) = (serviceProvider, logger);

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation(
            $"{nameof(ScopedBackgroundService)} is running.");

        await DoWorkAsync(stoppingToken);
    }

    private async Task DoWorkAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation(
            $"{nameof(ScopedBackgroundService)} is working.");

        using (IServiceScope scope = _serviceProvider.CreateScope())
        {
            IScopedProcessingService scopedProcessingService =
                scope.ServiceProvider.GetRequiredService<IScopedProcessingService>();

            await scopedProcessingService.DoWorkAsync(stoppingToken);
        }
    }

    public override async Task StopAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation(
            $"{nameof(ScopedBackgroundService)} is stopping.");

        await base.StopAsync(stoppingToken);
    }
}
Run Code Online (Sandbox Code Playgroud)

Program.cs 如下所示

using App.ScopedService;

using IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddHostedService<ScopedBackgroundService>();
        services.AddScoped<IScopedProcessingService, DefaultScopedProcessingService>();
    })
    .Build();

await host.RunAsync();
Run Code Online (Sandbox Code Playgroud)

如果我有另一个后台服务,那么我可以重复使用哪些所有代码以及如何解析范围服务?

Che*_*ery 7

您可以创建多个实现 IHostedService 接口的服务,然后像这样注册它们:

builder.Services.AddHostedService<HostedServiceA>();
builder.Services.AddHostedService<HostedServiceB>();
builder.Services.AddHostedService<HostedServiceC>();
Run Code Online (Sandbox Code Playgroud)

如果要访问单例内部的作用域服务,最简单的方法是在构造函数中注入IServiceScopeFactory

public HostedServiceA(IServiceScopeFactory serviceScopeFactory)
{
    _serviceScopeFactory = serviceScopeFactory ?? throw new ArgumentNullException(nameof(serviceScopeFactory));
}
Run Code Online (Sandbox Code Playgroud)

然后您可以通过调用以下方法来访问方法内的作用域服务:

using var scope = _serviceScopeFactory.CreateScope();
var someScopedService = scope.ServiceProvider.GetService<ISomeScopedService>();
var someOtherScopedService = scope.ServiceProvider.GetService<ISomeOtherScopedService>();
Run Code Online (Sandbox Code Playgroud)