IHostedService:
适用于需要更高灵活性和控制的场景。
需要自定义启动和停止逻辑。
适用于复杂的后台任务管理。
BackgroundService:
适用于需要简单实现后台任务的场景。
提供了一个方便的抽象,减少样板代码。
适用于大多数常见的后台任务。
public class MyHostedService : IHostedService
{
private readonly ILogger<MyHostedService> _logger;
private Timer _timer;
public MyHostedService(ILogger<MyHostedService> logger)
{
_logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("MyHostedService is starting.");
_timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
return Task.CompletedTask;
}
private void DoWork(object state)
{
_logger.LogInformation("MyHostedService is working.");
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("MyHostedService is stopping.");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
在 BackgroundService 中,StopAsync 是用来优雅地停止服务的。当应用程序停止时,StopAsync 会被调用,并且 CancellationToken 会被触发,这将会请求 ExecuteAsync 停止运行。然而,StopAsync 并不会等待 ExecuteAsync 自行完成;相反,StopAsync 会立即开始执行。
为了确保 ExecuteAsync 完成后再执行 StopAsync 中的逻辑,可以在 ExecuteAsync 内部检测到取消请求时进行清理,然后将 ExecuteAsync 任务与 StopAsync 协调起来。
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<MyBackgroundService>();
})
.Build();
await host.RunAsync();
}
}
public class MyBackgroundService : BackgroundService
{
private readonly ILogger<MyBackgroundService> _logger;
private Task _executingTask;
private readonly IHostApplicationLifetime _applicationLifetime;
private CancellationTokenSource _stoppingCts = new CancellationTokenSource();
public MyBackgroundService(ILogger<MyBackgroundService> logger, IHostApplicationLifetime applicationLifetime)
{
_logger = logger;
_applicationLifetime = applicationLifetime;
}
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("MyBackgroundService is starting.");
stoppingToken.Register(() => _logger.LogInformation("MyBackgroundService is stopping."));
_executingTask = Task.Run(async () =>
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("MyBackgroundService is running.");
await Task.Delay(5000, stoppingToken);
}
_logger.LogInformation("MyBackgroundService is completing background work.");
// 在这里添加任何清理逻辑,例如关闭资源等
_logger.LogInformation("MyBackgroundService has stopped.");
}, stoppingToken);
return _executingTask;
}
public override async Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("MyBackgroundService is executing StopAsync.");
// 请求停止
if (_executingTask == null)
{
return;
}
try
{
_stoppingCts.Cancel();
}
finally
{
// 等待任务完成
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
}
_logger.LogInformation("MyBackgroundService has completed StopAsync.");
}
public override void Dispose()
{
_stoppingCts.Cancel();
base.Dispose();
}
public async Task StopServiceAsync()
{
_logger.LogInformation("Stopping the service internally...");
_applicationLifetime.StopApplication();
}
}
参考:
BackgroundService Graceful Shutdown - Complete work and write to DB
https://stackoverflow.com/questions/70036809/backgroundservice-graceful-shutdown-complete-work-and-write-to-db