You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hangfire注入Scoped服务执行后台作业时的异常问题

问题解决方案

错误原因分析

第一个异常(变量未定义)

初始代码中,Enqueue<MyStorageService>(s => EnqueueJob(s)) 的写法存在逻辑问题:Hangfire 无法正确解析嵌套调用静态方法的表达式,s 作为参数的作用域无法被识别,导致表达式编译失败。另外,async void 类型的作业方法会导致 Hangfire 无法跟踪任务状态,也无法正确处理异常。

第二个异常(空引用)

你在控制器中提前创建作用域并获取 MyStorageService 实例,再将实例传递给 Hangfire 作业。但 Hangfire 会序列化作业参数,而Scoped 服务(如依赖的 EF Core DbContext)无法被正确序列化,当作业执行时,实例已脱离原作用域,内部依赖(如 DbContext)已失效或未被初始化,从而引发空引用异常。

正确实现方案

Hangfire 原生支持依赖注入,应让 Hangfire 在执行作业时自动创建作用域并解析 Scoped 服务,而非提前在控制器中实例化服务。

步骤1:创建独立的作业服务类

将作业逻辑封装到单独的类中,避免与控制器耦合,同时便于 Hangfire 解析依赖:

public class MyJobExecutor
{
    private readonly MyStorageService _storageService;

    // 通过构造函数注入Scoped服务
    public MyJobExecutor(MyStorageService storageService)
    {
        _storageService = storageService;
    }

    [JobDisplayName("My job"), DisableConcurrentExecution(10 * 60)]
    public async Task RunJobAsync()
    {
        await _storageService.DoAsync();
    }
}

步骤2:注册作业服务

在 Program.cs 中将作业服务注册为 Scoped(与 MyStorageService 生命周期一致):

builder.Services.AddScoped<MyJobExecutor>();

步骤3:修改控制器Action

在控制器中直接让 Hangfire 调度作业服务的方法,Hangfire 会自动处理依赖注入和作用域创建:

private readonly IBackgroundJobClient _backgroundJobClient;

// 控制器构造函数注入IBackgroundJobClient
public MyController(IBackgroundJobClient backgroundJobClient)
{
    _backgroundJobClient = backgroundJobClient;
}

[HttpPost]
public string DoSomething()
{
    // 让Hangfire自动解析MyJobExecutor并执行作业
    var jobId = _backgroundJobClient.Enqueue<MyJobExecutor>(executor => executor.RunJobAsync());
    return jobId;
}

步骤4:确保Hangfire配置正确

在 Program.cs 配置 Hangfire 时,确保使用应用的服务提供器:

builder.Services.AddHangfire(config =>
{
    // 配置Hangfire存储(如SQL Server、Redis等)
    config.UseSqlServerStorage(builder.Configuration.GetConnectionString("HangfireConnection"));
    // 关联应用的服务提供器,支持依赖注入
    config.UseServiceProviderFactory(new DefaultServiceProviderFactory());
});

builder.Services.AddHangfireServer();

关键注意事项

  • 作业方法必须返回 async Task,禁止使用 async void,否则 Hangfire 无法跟踪任务完成状态和处理异常。
  • Scoped 服务(如 MyStorageService、EF Core DbContext)只能由 Hangfire 在作业执行时解析,不能提前实例化后传递给作业。
  • Hangfire 会为每个作业创建独立的作用域,作业执行完成后自动释放作用域内的所有服务,避免资源泄漏。

内容的提问来源于stack exchange,提问作者Sam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 12:59:15