BackgroundService 是 ASP.NET Core 中实现长运行托管后台任务的标准方式,需继承并重写 ExecuteAsync,使用 CancellationToken 响应关闭,通过 AddHostedService 注册,支持 DI 但需注意作用域生命周期。

在 C#(特别是 .NET 5+ 的 ASP.NET Core 应用中),BackgroundService 是实现**长运行、托管后台任务**的标准方式。它由 IServiceCollection 托管,随应用启动/停止自动生命周期管理,比裸写线程或 Task.Run 更安全、更可控。
1. 继承 BackgroundService 并重写 ExecuteAsync
核心是继承 BackgroundService,并重写 ExecuteAsync(CancellationToken stoppingToken) 方法。该方法会被框架调用一次,你需在此内部实现持续运行的逻辑(通常用循环 + 延迟)。
- 必须使用
stoppingToken检查取消请求,确保能响应应用关闭 - 避免直接用
while(true)死循环,要用await Task.Delay(..., stoppingToken)支持中断 - 异常未捕获会导致后台服务意外终止(不会自动重启)
示例:每 5 秒打印一次时间
public class ClockService : BackgroundService
{
private readonly ILogger _logger;
public ClockService(ILogger logger) => _logger = logger;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("当前时间: {Time}", DateTime.Now);
await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
}
}
}
2. 在 Program.cs 中注册为托管服务
.NET 6+ 推荐在 Program.cs 的服务容器中注册,使用 AddHostedService 或 AddScoped(推荐前者)。
- 注册后,框架会在应用启动时调用
StartAsync,关闭时调用StopAsync - 服务默认是单例生命周期,无需手动管理实例
注册代码(Program.cs):
Sylius开源电子商务平台是一个开源的 PHP 电子商务网站框架,基于 Symfony 和 Doctrine 构建,为用户量身定制解决方案。可管理任意复杂的产品和分类,每个产品可以设置不同的税率,支持多种配送方法,集成 Omnipay 在线支付。功能特点:前后端分离Sylius 带有一个强大的 REST API,可以自定义并与您选择的前端或您的微服务架构很好地配合使用。如果您是 Symfony
var builder = WebApplication.CreateBuilder(args); // 注册后台服务(自动托管) builder.Services.AddHostedService(); // 其他服务... builder.Services.AddControllers(); var app = builder.Build(); app.MapControllers(); app.Run();
3. 使用依赖注入(DI)获取其他服务
BackgroundService 支持构造函数注入,可安全使用 ILogger、IConfiguration、数据库上下文(注意:若用 EF Core,请用 IServiceScopeFactory 创建作用域,避免跨作用域共享 DbContext)。
- 不要在后台服务中长期持有 scoped 服务(如 DbContext),应按需创建新 scope
- 需要访问数据库时,建议通过
IServiceScopeFactory创建临时 scope
带数据库操作的片段示例:
public class DataSyncService : BackgroundService
{
private readonly IServiceScopeFactory _scopeFactory;
private readonly ILogger _logger;
public DataSyncService(IServiceScopeFactory scopeFactory, ILogger logger)
{
_scopeFactory = scopeFactory;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
using var scope = _scopeFactory.CreateScope();
var context = scope.ServiceProvider.GetRequiredService();
// 执行查询或保存...
var count = await context.Users.CountAsync(stoppingToken);
_logger.LogInformation("用户总数: {Count}", count);
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
}
}
}
4. 启动与停止的注意事项
BackgroundService 的 StartAsync 和 StopAsync 是可重写的,但多数场景无需干预。需注意:
-
StopAsync有默认 5 秒超时(可通过IHostOptions.ShutdownTimeout修改) - 若你的清理逻辑耗时较长,应在
stoppingToken触发后尽快退出循环,并在StopAsync中做收尾(如释放资源、提交事务) - 不建议在
StopAsync中执行阻塞 IO 或长时间等待 —— 应配合stoppingToken提前退出
基本上就这些。用好 BackgroundService 关键就三点:正确响应取消令牌、合理使用 DI、避免在后台任务里滥用生命周期不匹配的服务。它不是万能定时器(复杂调度建议用 Quartz.NET 或 Hangfire),但对轻量级周期性任务非常够用。









