C#怎么配置后台任务 BackgroundService使用方法

来源:这里教程网 时间:2026-02-21 17:34:18 作者:

在 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<ClockService> _logger;
    public ClockService(ILogger<ClockService> 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<t>()</t>
AddScoped<t>().AddHostedService(x => x.GetRequiredService<t>())</t></t>
(推荐前者)。

注册后,框架会在应用启动时调用
StartAsync
,关闭时调用
StopAsync
服务默认是单例生命周期,无需手动管理实例

注册代码(Program.cs):

var builder = WebApplication.CreateBuilder(args);
// 注册后台服务(自动托管)
builder.Services.AddHostedService<ClockService>();
// 其他服务...
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<DataSyncService> _logger;
    public DataSyncService(IServiceScopeFactory scopeFactory, ILogger<DataSyncService> 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<AppDbContext>();
            // 执行查询或保存...
            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),但对轻量级周期性任务非常够用。

相关推荐