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

.NET 8 + Quartz 3.11作业依赖注入配置失败问题及解决

问题:.NET 8 + Quartz 3.11 带参构造函数作业无法注入依赖

在使用.NET 8和Quartz 3.11实现IJob接口的作业时,遇到依赖注入失效问题:带参数构造函数的作业(如EventWithoutDrawReminderJob)无法注入所需依赖,仅空构造函数能正常执行。已配置必要的依赖项但无效,尝试使用UseMicrosoftDependencyInjectionJobFactory()方法,但该方法已标记为即将废弃,且现有相关资料多为多年前发布的内容。


问题代码:AddJobServices扩展方法

public static async Task<IServiceCollection> AddJobServices(this IServiceCollection services)
{
    services.AddQuartz(q =>
    {
        q.UseMicrosoftDependencyInjectionJobFactory();
        q.UseInMemoryStore();
        q.UseDedicatedThreadPool(tp =>
        {
            tp.MaxConcurrency = 10;
        });

        
        q.AddJob<EventWithoutDrawReminderJob>(opts => opts
            .WithIdentity(nameof(EventWithoutDrawReminderJob))
            .StoreDurably()
            .RequestRecovery());
    });
    
    services.AddQuartzHostedService(options =>
    {
        options.WaitForJobsToComplete = true;
        options.AwaitApplicationStarted = true;
    });
    
    // 向DI容器注册作业
    services.AddTransient<EventWithoutDrawReminderJob>();
    
    var quartzProperties = new NameValueCollection
    {
        ["quartz.serializer.type"] = "newtonsoft"
    };
    var factory = new StdSchedulerFactory(quartzProperties);
    var list = await factory.GetAllSchedulers(); // 测试用,返回空列表
    var scheduler = await factory.GetScheduler();
    scheduler.Start().Wait();
    
    services.AddSingleton(scheduler);

    return services;
}

作业类定义:EventWithoutDrawReminderJob

public class EventWithoutDrawReminderJob : IJob
{
    public IApplicationDbContext DbContext { get; set; }
    public INotificationService NotificationService { get; set; }
    public UserManager<ApplicationUser> UserManager { get; set; }
    public RoleManager RoleManager { get; set; }
    public ILogger Logger { get; set; }

    // public EventWithoutDrawReminderJob()
    // {
    //     Console.WriteLine(" > Starting JobExecution: EventWithoutDrawReminderJob"); // 取消注释后断点会命中此处
    // }

    public EventWithoutDrawReminderJob(ApplicationDbContext dbContext,
        INotificationService notificationService, 
        UserManager<ApplicationUser> userManager,
        RoleManager roleManager,
        ILogger logger)
    {
        // 此代码从未执行
        DbContext = dbContext;
        NotificationService = notificationService;
        UserManager = userManager;
        RoleManager = roleManager;
        Logger = logger;
    }

    public async Task Execute(IJobExecutionContext context)
    {
        // 使用依赖的业务代码
    }
}

Program.cs调用代码

...
builder.Services.AddApplicationServices(appSettings);
await builder.Services.AddJobServices();
...

AddApplicationServices扩展方法

public static IServiceCollection AddApplicationServices(this IServiceCollection services, IAppConfigurations appSettings)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(configuration.GetConnectionString("testDB"),
            builder =>
            {
                builder.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName);
                builder.EnableRetryOnFailure(3);
                builder.CommandTimeout(30);
            }
        ));

    services.AddScoped<IApplicationDbContext>(provider => provider.GetRequiredService<ApplicationDbContext>());
    
    // 配置Identity
    services
        .AddIdentityCore<ApplicationUser>(options =>
        {
            options.Password.RequiredLength = 6;
            options.Password.RequireNonAlphanumeric = false;
            options.Password.RequireLowercase = false;
            options.Password.RequireUppercase = false;
            options.Password.RequireDigit = false;
        })
        .AddRoles<ApplicationRole>()
        .AddTokenProvider<DataProtectorTokenProvider<ApplicationUser>>(TokenOptions.DefaultProvider)
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    services
        .AddScoped<ApplicationUserManager>()
        .AddScoped<RoleManager>();
    
    services.AddScoped<INotificationService, NotificationService>();
    
    return services;
}

解决方案

该方案包含Quartz作业和触发器的仪表盘功能,需先在项目中安装SilkierQuartz,之后在Program.cs中调用builder.Services.AddJobServices();即可。

配置代码:AddJobServices扩展方法

public static IServiceCollection AddJobServices(this IServiceCollection services)
{
    services.AddTransient<MyJob>();

    // 添加Quartz服务
    services.AddQuartz(q =>
    {
        q.SchedulerName = "example-scheduler";
        
        q.UseDedicatedThreadPool(tp =>
        {
            tp.MaxConcurrency = 5;
        });
        
        // 初始配置使用内存存储,如需切换持久化存储请注释此行并启用下方的UsePersistentStore
        // q.UseInMemoryStore();
        
        // 可切换为SQL Server等持久化存储
        q.UsePersistentStore(s =>
        {
            s.PerformSchemaValidation = true; 
            s.UseProperties = true; 
            s.RetryInterval = TimeSpan.FromSeconds(30);
            s.UseSqlServer(sqlServer =>
            {
                sqlServer.ConnectionString = "your connection string";
                sqlServer.TablePrefix = "QRTZ_";
            });
            s.UseNewtonsoftJsonSerializer();
            s.UseClustering(c =>
            {
                c.CheckinMisfireThreshold = TimeSpan.FromSeconds(20);
                c.CheckinInterval = TimeSpan.FromSeconds(10);
            });
        });
        
        // 注册作业
        q.AddJob<MyJob>(opts => opts
            .WithIdentity(nameof(MyJob))
            .StoreDurably()
            .RequestRecovery());
        
        // 如需配置触发器可取消注释
        // q.AddTrigger(opts => opts
        //     .ForJob(nameof(WeeklyEventsMailingJob))
        //     .WithIdentity("WeeklyEventsMailingTrigger")
        //     .WithCronSchedule("0 0 5 ? * MON *")
        //     .StartNow());
    });
    
    services.AddQuartzHostedService(options =>
    {
        options.WaitForJobsToComplete = true;
        options.AwaitApplicationStarted = true;
    });
    
    // 配置SilkierQuartz仪表盘
    services.AddSingleton(new SilkierQuartzOptions
    {
        VirtualPathRoot = "/quartz",
        UseLocalTime = true,
        ProductName = "ExampleApp",
        DefaultDateFormat = "yyyy-MM-dd",
        DefaultTimeFormat = "HH:mm:ss",
        CronExpressionOptions = new CronExpressionDescriptor.Options()
        {
            DayOfWeekStartIndexZero = false // Quartz使用1-7表示星期几
        }
    });
    services.AddSingleton(new SilkierQuartzAuthenticationOptions
    {
        AccessRequirement = SilkierQuartzAuthenticationOptions.SimpleAccessRequirement.AllowAnonymous
    });
    services.AddAuthorization(
        opts => opts.AddPolicy(
            "SilkierQuartz",
            builder => builder.AddRequirements(
                new SilkierQuartzDefaultAuthorizationRequirement(
                    SilkierQuartzAuthenticationOptions.SimpleAccessRequirement.AllowAnonymous))));
    services.AddScoped<IAuthorizationHandler, SilkierQuartzDefaultAuthorizationHandler>();

    return services;
}

调度器使用示例

后续使用调度器时,需注入ISchedulerFactory并获取IScheduler实例,以支持带依赖构造函数的作业:

public class MyServiceClass
{
    public ISchedulerFactory SchedulerFactory { get; set; }
    public IScheduler Scheduler { get; set; }

    public MyServiceClass(ISchedulerFactory schedulerFactory, ...)
    {
        SchedulerFactory = schedulerFactory;
        Scheduler = schedulerFactory.GetScheduler().Result;
        ...
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 17:57:33