.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
相关产品推荐
相关产品推荐

