您需要创建一个实现IHostedService 的类。该接口只定义了两个方法,StartAsync 在应用程序启动时调用,StopAsync 在应用程序终止时调用。
您需要将其注册为托管服务:
services.AddHostedService<TimedHostedService>();
小心使用AddHostedService,不要 AddSingleton。如果您使用AddSingleton,运行时将不知道在适当的时候调用 StartAsync 和 StopAsync。
文章Background tasks with hosted services in ASP.NET Core 展示了如何使用计时器实现服务:
internal class TimedHostedService : IHostedService, IDisposable
{
private readonly ILogger _logger;
private Timer _timer;
public TimedHostedService(ILogger<TimedHostedService> logger)
{
_logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is starting.");
_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromSeconds(10));
return Task.CompletedTask;
}
private void DoWork(object state)
{
_logger.LogInformation("Timed Background Service is working.");
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is stopping.");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
这段代码没有什么特别有趣的地方 - 只需在调用 StartAsync 时启动一个计时器,然后在 StopAsync 上停止它
取消长时间运行的任务
当运行时需要回收或停止时,它会在所有托管服务上调用StopAsync 方法,等待它们优雅地完成,然后警告它们立即取消。片刻之后,它将继续并终止应用程序或回收它。
cancellationToken 参数用于指示服务应立即停止。通常,这意味着您必须编写自己的代码来检查它,警告您自己的任务终止,等待所有任务完成等,类似于代码shown in this article
不过,这几乎是样板文件,这就是为什么 BackgroundService 类可用于创建只需要实现 ExecuteAsync(CancellationToken) 的类。启动和停止该任务由BackgroundService 提供,例如:
public class PollingService : BackgroundService
{
private readonly ILogger _logger;
public PollingService(ILogger<PollingService> logger)
{
_logger = logger;
}
protected async override Task ExecuteAsync(
CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
await DoSomething(cancellationToken);
await Task.Delay(1000,cancellationToken);
}
catch (Exception ex)
{
_logger.LogError(ex,
$"Error occurred executing {nameof(workItem)}.");
}
}
_logger.LogInformation("Queued Hosted Service is stopping.");
}
}
在这种情况下,Task.Delay() 本身将在运行时引发取消令牌后立即被取消。 DoSomething() 本身应该以检查取消令牌的方式实现,例如将其传递给任何接受它作为参数的异步方法,在每个循环上测试 IsCancellationRequested 属性并退出它。
例如:
protected async override Task ExecuteAsync(
CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
foreach (var ext in GetExtensions())
{
//Oops, time to cancel
if(cancellationToken.IsCancellationRequested)
{
break;
}
//Otherwise, keep working
ext.Status = StatusType.Available;
}
await Task.Delay(1000,cancellationToken);
}
catch (Exception ex)
{
...
}
}
_logger.LogInformation("Hosted Service is stopping.");
}