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)
如果我有另一个后台服务,那么我可以重复使用哪些所有代码以及如何解析范围服务?
您可以创建多个实现 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)