使用Quartz.NET+DI的控制台应用无法创建无空构造函数的Job
问题:Quartz Job无法通过依赖注入获取依赖对象,报错无空构造函数
报错信息:
Problem instantiating class 'test.MyJob: Cannot instantiate type which has no empty constructor (Parameter 'MyJob')'
用户代码如下:
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Quartz; using System.Diagnostics; namespace test { internal class Program { static async Task Main(string[] args) { var host = Host.CreateDefaultBuilder() .ConfigureServices((_, services) => { services.AddTransient<MyJob>(); services.AddTransient<IDog, Dog>(); services.AddQuartz(q => { q.ScheduleJob<MyJob>(trigger => trigger .WithDailyTimeIntervalSchedule(x => x.WithInterval(10, IntervalUnit.Second)) ); }); services.AddQuartzHostedService(); }) .Build(); await host.RunAsync(); } } public interface IDog { string Name { get; } } public class Dog : IDog { public string Name => "Doge"; } class MyJob : IJob { IDog _dog; public MyJob(IDog dog) { _dog= dog; } public Task Execute(IJobExecutionContext context) { Debug.WriteLine($"{_dog.Name} says {DateTime.Now}"); return Task.CompletedTask; } } }
项目文件:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net7.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.0" /> <PackageReference Include="Quartz" Version="3.5.0" /> <PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.5.0" /> <PackageReference Include="Quartz.Extensions.Hosting" Version="3.5.0" /> </ItemGroup> </Project>
原因与解决方法
原因
Quartz默认的作业实例化逻辑是直接调用Job类型的构造函数,不会从依赖注入容器中获取实例。即使你把MyJob注册到了DI容器,ScheduleJob<T>的默认用法并没有告诉Quartz要使用DI来解析Job对象,所以它找不到无参构造函数就会抛出这个错误。
解决方法
方法一:显式注册Job并关联触发器
通过AddJob方法注册Job,明确指定从DI容器解析实例,再创建触发器关联该Job:
services.AddQuartz(q => { var jobKey = new JobKey("MyJob"); // 注册Job,指定使用DI解析 q.AddJob<MyJob>(jobKey, j => j.WithIdentity(jobKey)); // 创建触发器并绑定到Job q.AddTrigger(t => t .WithIdentity("MyJobTrigger") .ForJob(jobKey) .WithDailyTimeIntervalSchedule(x => x.WithInterval(10, IntervalUnit.Second)) ); });
方法二:全局配置DI作业工厂
配置Quartz使用Microsoft的DI作业工厂,这样所有Job都会自动从DI容器中获取实例,原有的ScheduleJob<T>代码可以保留:
services.AddQuartz(q => { // 启用DI作业工厂,全局生效 q.UseMicrosoftDependencyInjectionJobFactory(); q.ScheduleJob<MyJob>(trigger => trigger .WithDailyTimeIntervalSchedule(x => x.WithInterval(10, IntervalUnit.Second)) ); });
两种方法都能解决问题,方法一适合针对单个Job配置,方法二是全局生效的配置,根据实际需求选择即可。
内容的提问来源于stack exchange,提问作者Damn Vegetables
相关产品推荐
相关产品推荐

