如何在ASP.NET 6.0运行时动态调度Quartz.Net作业
实现ASP.NET Core 6.0运行时管理Quartz.Net作业触发器的方案
一、基础DI整合配置
先完成Quartz.Net与ASP.NET Core的依赖注入整合,在Program.cs中初始化核心组件,不硬编码具体任务:
builder.Services.AddQuartz(q => { // 让作业能通过DI获取服务实例 q.UseMicrosoftDependencyInjectionJobFactory(); // 配置SQLite持久化(适配树莓派轻量场景,避免重启丢失任务) q.UsePersistentStore(s => { s.UseSqlite("Data Source=quartz.db"); s.UseJsonSerializer(); }); }); // 注册Quartz后台服务,确保任务持续运行 builder.Services.AddQuartzServer(options => { options.WaitForJobsToComplete = true; });
二、构建参数模型与Cron转换逻辑
- 定义接收前端参数的模型:
public class JobTriggerRequest { public string JobName { get; set; } public string JobGroup { get; set; } public int[] SelectedWeekDays { get; set; } // 前端传入:1=周一,7=周日 public TimeSpan TriggerTime { get; set; } public string JobDescription { get; set; } }
- 实现星期+时间转Cron表达式的逻辑(注意Quartz周字段规则:1=周日,2=周一…7=周六,需做映射):
private string GenerateCronExpression(TimeSpan time, int[] weekDays) { // 把前端的周一(1)映射为Quartz的2,以此类推 var mappedWeekDays = weekDays.Select(d => d + 1); var weekDayStr = string.Join(",", mappedWeekDays); // Cron格式:秒 分 时 日 月 周 年(可选),日字段用?避免与周字段冲突 return $"{time.Second} {time.Minute} {time.Hours} ? * {weekDayStr}"; }
三、控制器中实现运行时作业管理
直接在控制器注入IScheduler,编写添加、更新、删除作业的接口:
[ApiController] [Route("api/job")] public class JobController : ControllerBase { private readonly IScheduler _scheduler; public JobController(IScheduler scheduler) { _scheduler = scheduler; } // 添加新作业 [HttpPost("add")] public async Task<IActionResult> AddJob([FromBody] JobTriggerRequest request) { // 构建作业详情(假设你的继电器控制作业类为RelayControlJob) var jobDetail = JobBuilder.Create<RelayControlJob>() .WithIdentity(request.JobName, request.JobGroup) .WithDescription(request.JobDescription) .Build(); // 生成Cron触发器 var cronExpr = GenerateCronExpression(request.TriggerTime, request.SelectedWeekDays); var trigger = TriggerBuilder.Create() .WithIdentity($"{request.JobName}-trigger", request.JobGroup) .WithCronSchedule(cronExpr) .Build(); // 提交调度 await _scheduler.ScheduleJob(jobDetail, trigger); return Ok("作业已添加"); } // 更新现有触发器 [HttpPost("update")] public async Task<IActionResult> UpdateTrigger([FromBody] JobTriggerRequest request) { var triggerKey = new TriggerKey($"{request.JobName}-trigger", request.JobGroup); var existingTrigger = await _scheduler.GetTrigger(triggerKey); if (existingTrigger == null) return NotFound("触发器不存在"); // 生成新Cron规则并更新触发器 var cronExpr = GenerateCronExpression(request.TriggerTime, request.SelectedWeekDays); var newTrigger = existingTrigger.GetTriggerBuilder() .WithCronSchedule(cronExpr) .Build(); await _scheduler.RescheduleJob(triggerKey, newTrigger); return Ok("触发器已更新"); } // 删除作业 [HttpDelete("remove")] public async Task<IActionResult> RemoveJob(string jobName, string jobGroup) { var jobKey = new JobKey(jobName, jobGroup); var result = await _scheduler.DeleteJob(jobKey); return result ? Ok("作业已删除") : NotFound("作业不存在"); } // Cron表达式生成方法 private string GenerateCronExpression(TimeSpan time, int[] weekDays) { var mappedWeekDays = weekDays.Select(d => d + 1); var weekDayStr = string.Join(",", mappedWeekDays); return $"{time.Second} {time.Minute} {time.Hours} ? * {weekDayStr}"; } }
四、作业类实现(以继电器控制为例)
编写具体的作业逻辑类,通过DI注入设备操作服务:
public class RelayControlJob : IJob { private readonly IRelayService _relayService; // 依赖注入设备服务 public RelayControlJob(IRelayService relayService) { _relayService = relayService; } public async Task Execute(IJobExecutionContext context) { // 执行继电器控制逻辑,比如开关切换 await _relayService.ToggleRelay(); } }
记得将IRelayService及其实现类注册到DI容器中。
五、前端闹钟式界面实现
用简单的HTML+JS构建作业配置表单,提交数据到后端接口:
<form id="jobForm"> <div> <label>作业名称:</label> <input type="text" name="jobName" required> </div> <div> <label>作业分组:</label> <input type="text" name="jobGroup" value="RelayJobs"> </div> <div> <label>选择星期:</label> <input type="checkbox" name="weekDays" value="1">周一 <input type="checkbox" name="weekDays" value="2">周二 <input type="checkbox" name="weekDays" value="3">周三 <input type="checkbox" name="weekDays" value="4">周四 <input type="checkbox" name="weekDays" value="5">周五 <input type="checkbox" name="weekDays" value="6">周六 <input type="checkbox" name="weekDays" value="7">周日 </div> <div> <label>触发时间:</label> <input type="time" name="triggerTime" required> </div> <div> <label>作业描述:</label> <textarea name="jobDescription"></textarea> </div> <button type="submit">添加作业</button> </form> <script> document.getElementById('jobForm').addEventListener('submit', async (e) => { e.preventDefault(); const formData = new FormData(e.target); const weekDays = Array.from(formData.getAll('weekDays')).map(Number); const timeParts = formData.get('triggerTime').split(':'); const requestData = { jobName: formData.get('jobName'), jobGroup: formData.get('jobGroup'), selectedWeekDays: weekDays, triggerTime: { hours: parseInt(timeParts[0]), minutes: parseInt(timeParts[1]), seconds: 0 }, jobDescription: formData.get('jobDescription') }; const response = await fetch('/api/job/add', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestData) }); alert(await response.text()); }); </script>
六、树莓派部署注意事项
- 发布时选择
.NET 6的linux-arm或linux-arm64架构,适配树莓派硬件 - 用SQLite持久化无需额外安装数据库,轻量易维护
- 将程序注册为系统服务,确保树莓派开机自动启动作业调度服务
内容的提问来源于stack exchange,提问作者oglcn
相关产品推荐
相关产品推荐

