.NET 5 Web API控制器中手动触发Quartz.NET任务及解决IScheduler依赖注入异常方案
解决Quartz.NET IScheduler注入失败及任务管理问题
1. 修复IScheduler注入异常
你遇到的InvalidOperationException是因为Quartz.NET默认不会把IScheduler直接注册到ASP.NET Core的依赖注入容器里,正确的做法是注入ISchedulerFactory,然后通过它来获取调度器实例。另外注意你原来的控制器中注入的ILogger<WeatherForecastController>是错误的,应该改为ILogger<QuartzController>,避免日志上下文错误。
修改后的QuartzController代码如下:
[ApiController] [Route("[controller]")] public class QuartzController : ControllerBase { private readonly ISchedulerFactory _schedulerFactory; private readonly ILogger<QuartzController> _logger; // 注入ISchedulerFactory而非直接IScheduler public QuartzController(ISchedulerFactory schedulerFactory, ILogger<QuartzController> logger) { _schedulerFactory = schedulerFactory; _logger = logger; } [HttpGet("Run")] public async Task<IActionResult> Run(string jobName) { // 获取调度器实例 var scheduler = await _schedulerFactory.GetSchedulerAsync(); // 构建任务Key(注意要和你注册任务时的Key一致) var jobKey = new JobKey(jobName); // 1. 检查任务是否存在 var jobExists = await scheduler.CheckExistsAsync(jobKey); if (!jobExists) { _logger.LogWarning("任务 {JobName} 不存在", jobName); return NotFound($"任务 {jobName} 不存在"); } // 2. 手动触发任务 await scheduler.TriggerJobAsync(jobKey); _logger.LogInformation("任务 {JobName} 已触发", jobName); // 3. 获取任务及触发器相关状态 var jobDetail = await scheduler.GetJobDetailAsync(jobKey); // 获取任务绑定的所有触发器状态 var triggers = await scheduler.GetTriggersOfJobAsync(jobKey); var triggerStates = new Dictionary<string, TriggerState>(); foreach (var trigger in triggers) { var state = await scheduler.GetTriggerStateAsync(trigger.Key); triggerStates.Add(trigger.Key.Name, state); } // 获取当前正在运行的任务(如果需要确认任务是否正在执行) var runningJobs = await scheduler.GetCurrentlyExecutingJobsAsync(); var isJobRunning = runningJobs.Any(j => j.JobDetail.Key.Equals(jobKey)); var response = new { Message = $"任务 {jobName} 已成功触发", JobDescription = jobDetail.Description, IsJobRunning = isJobRunning, TriggerStates = triggerStates }; return Ok(response); } }
2. 确保JobKey与注册时一致
你使用的AddJobAndTrigger方法通常会根据任务类型生成JobKey,默认是用任务类的完整命名空间+类名作为JobKey的Name(比如QuartzTest.HelloWorldJob),而不是简单的HelloWorldJob。如果想自定义JobKey,可以修改注册逻辑,显式指定任务标识:
services.AddQuartz(q => { q.UseMicrosoftDependencyInjectionJobFactory(); // 显式指定JobKey,方便后续调用 q.AddJob<HelloWorldJob>(job => job.WithIdentity("HelloWorldJob")); // 绑定触发器(示例:每5秒执行一次,可根据配置调整) q.AddTrigger(trigger => trigger .ForJob("HelloWorldJob") .WithIdentity("HelloWorldJob-Trigger") .WithCronSchedule("0/5 * * * * ?")); });
3. 关键API说明
CheckExistsAsync(jobKey):验证指定JobKey的任务是否已注册到调度器TriggerJobAsync(jobKey):手动触发指定任务,不管其原有触发器配置GetTriggerStateAsync(triggerKey):获取触发器状态(比如Normal正常调度、Paused暂停、Completed已完成等)GetCurrentlyExecutingJobsAsync():获取当前正在运行的所有任务,可用来判断目标任务是否处于执行状态
内容的提问来源于stack exchange,提问作者Misiu




