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

.NET 6控制台Hangfire定时任务依赖注入报错求助

问题分析与修复方案

问题根源

  1. 作业注册方式错误:使用闭包() => _adminService.PruneOtpBackups()时,Hangfire会尝试序列化该闭包中的_adminService实例,失败后会直接尝试创建AdminService类型,但该类型无无参构造函数,导致异常。
  2. 自定义JobActivator未生效:Executor中手动创建了BackgroundJobServer,未应用之前配置的自定义Activator;同时原Activator的Scope管理错误,导致服务实例提前被释放。
  3. Host生命周期破坏:在ConfigureServices阶段提前构建服务提供者并执行Execute,违背了.NET Host的生命周期管理逻辑。

具体修复步骤

1. 修改作业注册方式,依赖Activator解析服务

将Executor中的定时任务注册改为直接指定服务类型的方式,让Hangfire通过自定义Activator解析IAdminService:

public void Execute()
{
    try
    {
        // 直接指定服务类型,让Hangfire通过Activator获取实例
        RecurringJob.AddOrUpdate<IAdminService>(
            adminService => adminService.PruneOtpBackups(), 
            "*/2 * * * *");

        Console.WriteLine("Hangfire Server started. Press any key to exit...");
        Console.ReadKey();
    }
    catch (Exception ex)
    {
        Log.Error(ex, "An error occurred!");
        throw;
    }
    finally
    {
        Log.CloseAndFlush();
    }
}

2. 修正自定义JobActivator的Scope管理

原Activator中使用using var scope会导致Scope在方法结束后立即释放,服务实例被提前回收。重写BeginScope方法,让Scope与Job生命周期绑定:

using Hangfire;
using Microsoft.Extensions.DependencyInjection;

namespace Infrabel.Account.JobScheduler
{
    public class HangfireActivator : JobActivator
    {
        private readonly IServiceScopeFactory _scopeFactory;

        public HangfireActivator(IServiceScopeFactory scopeFactory)
        {
            _scopeFactory = scopeFactory;
        }

        public override JobActivatorScope BeginScope(JobActivatorContext context)
        {
            var scope = _scopeFactory.CreateScope();
            return new HangfireScope(scope);
        }

        private class HangfireScope : JobActivatorScope
        {
            private readonly IServiceScope _scope;

            public HangfireScope(IServiceScope scope)
            {
                _scope = scope;
            }

            public override object Resolve(Type type)
            {
                return _scope.ServiceProvider.GetRequiredService(type);
            }

            public override void DisposeScope()
            {
                _scope.Dispose();
            }
        }
    }
}

3. 移除手动创建的BackgroundJobServer,依赖Host托管

AddHangfireServer()已经将Hangfire Server注册为Host托管服务,会自动启动,无需手动创建。删除Executor中using (var server = new BackgroundJobServer())代码块。

4. 修正Program.cs的Host配置逻辑

不在ConfigureServices中提前构建服务提供者,改为Host启动后获取Executor实例执行:

using IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((context, services) =>
    {
        var connString = "ConnString"; // 建议从配置文件读取,例如context.Configuration.GetConnectionString("Hangfire")
        services.AddAccountLib(connString);
        
        services.AddHangfire((provider, config) =>
        {
            config.UseSqlServerStorage(connString)
                  .UseActivator(new HangfireActivator(provider.GetRequiredService<IServiceScopeFactory>()));
        });
        
        services.AddHangfireServer(); // 注册Hangfire托管服务
        services.AddSingleton<Executor>();
    })
    .Build();

// Host启动后获取Executor执行
var executor = host.Services.GetRequiredService<Executor>();
executor.Execute();

await host.RunAsync();

额外验证点

  • 确认AddAccountLib方法已正确注册IAdminService与AdminService的映射关系,且生命周期配置合理(如Scoped/Singleton)。
  • 确保Hangfire数据库连接字符串正确,可通过Hangfire.SqlServer.SqlServerStorage.CreateTablesIfNotExists()手动初始化数据库表。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 00:43:22