在 ASP.NET Core 中每 5 分钟运行一次异步托管服务

lon*_*nix 19 c# async-await asp.net-core asp.net-core-hosted-services asp.net-core-5.0

后台服务的ASP.NET Core文档显示了许多实现示例。

有一个在计时器上启动服务的示例,尽管它是同步的。还有另一个异步示例,用于启动具有范围依赖项的服务。

我需要同时执行这两项操作:每 5 分钟启动一个服务,并且它具有范围内的依赖项。没有这样的例子。

我结合了这两个示例,但我不确定使用Timerasync 的安全方法TimerCallback

例如

public class MyScheduler : IHostedService
{
  private Timer? _timer;
  private readonly IServiceScopeFactory _serviceScopeFactory;

  public MyScheduler(IServiceScopeFactory serviceScopeFactory) => _serviceScopeFactory = serviceScopeFactory;

  public void Dispose() => _timer?.Dispose();

  public Task StartAsync(CancellationToken cancellationToken)
  {
    _timer = new Timer((object? state) => {
      using var scope = _serviceScopeFactory.CreateScope();
      var myService = scope.ServiceProvider.GetRequiredService<IMyService>();
      await myService.Execute(cancellationToken);            // <------ problem
    }), null, TimeSpan.Zero, TimeSpan.FromSeconds(5));

    return Task.CompletedTask;
  }

  public Task StopAsync(CancellationToken cancellationToken) {
    _timer?.Change(Timeout.Infinite, 0);
    return Task.CompletedTask;
  }

}
Run Code Online (Sandbox Code Playgroud)

计时器需要同步回调,所以问题是await. 调用异步服务的安全方法是什么?

Art*_*tur 39

使用BackgroundService而不是IHostedService

public class MyScheduler : BackgroundService
{
    private readonly IServiceScopeFactory _serviceScopeFactory;
    public MyScheduler(IServiceScopeFactory serviceScopeFactory) => _serviceScopeFactory = serviceScopeFactory;

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // Option 1
        while (!stoppingToken.IsCancellationRequested)
        {
            // do async work
            using (var scope = _serviceScopeFactory.CreateScope())
            {
              var myService = scope.ServiceProvider.GetRequiredService<IMyService>();
              await myService.Execute(stoppingToken);
            }
            await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
        }

        // Option 2 (.NET 6)
        using var timer = new PeriodicTimer(TimeSpan.FromMinutes(5));
        while (await timer.WaitForNextTickAsync(stoppingToken))
        {
            // do async work
            // ...as above
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您的问题有“asp.net-core-5”标签,但请注意,.NET 5.0 已于 [2022 年 8 月 5 日停止支持](https://dotnet.microsoft.com/en-us) /platform/support/policy/dotnet-core),因此您最好升级到 6.0 并使用 `PeriodicTimer`。 (3认同)