Quartz.NET使用WithCronSchedule报错:'?'后存在非法字符|
问题分析与解决方案
首先,你遇到的Illegal character after '?': |异常,根源是Quartz.NET的CronTrigger并不支持用|符号拼接多个Cron表达式——这个写法不是Quartz认可的语法,所以直接触发了非法字符报错。
你的需求是每日00:00和12:00各执行一次任务,这里有两种靠谱的实现方式,我分别给你讲清楚:
方案1:合并成单个Cron表达式
Cron表达式原生支持用逗号分隔多个时间值,所以你可以把两个时间点合并成一个表达式,这样只需要一个触发器就能搞定:
0 0 0,12 * * ?
这个表达式的含义就是:每天的0点整和12点整执行任务。
修正后的代码(合并Cron版)
我还修复了代码里的几个异步规范问题(比如async static void改成async static Task,避免用.Result/.Wait()阻塞,改用await):
public class JobScheduler { public async static Task Start() { // 合并后的Cron表达式 string cronExpression = "0 0 0,12 * * ?"; IScheduler scheduler = await StdSchedulerFactory.GetDefaultScheduler(); await scheduler.Start(); IJobDetail job = JobBuilder.Create<MyJobClass>() .WithIdentity("MyJobKey", "MyJobGroup") .Build(); ITrigger trigger = TriggerBuilder.Create() .WithDescription("DailyTwiceTrigger") .WithIdentity("MyJobTriggerKey", "MyJobGroup") // 触发器ID和Job区分开,避免冲突 .WithCronSchedule(cronExpression) .StartAt(DateTime.UtcNow) .WithPriority(1) .Build(); bool isExists = await scheduler.CheckExists(job.Key); if (isExists) { await scheduler.RescheduleJob(new TriggerKey("MyJobTriggerKey", "MyJobGroup"), trigger); } else { await scheduler.ScheduleJob(job, trigger); } } }
方案2:创建两个独立的触发器
如果你更倾向于保留两个独立的时间配置(比如后续可能要分别调整),可以给同一个Job绑定两个CronTrigger:
修正后的代码(双触发器版)
public class JobScheduler { public async static Task Start() { string noonJobCron = "0 0 12 * * ?"; string midnightJobCron = "0 0 0 * * ?"; IScheduler scheduler = await StdSchedulerFactory.GetDefaultScheduler(); await scheduler.Start(); IJobDetail job = JobBuilder.Create<MyJobClass>() .WithIdentity("MyJobKey", "MyJobGroup") .Build(); // 创建第一个触发器(中午12点) ITrigger noonTrigger = TriggerBuilder.Create() .WithDescription("NoonTrigger") .WithIdentity("NoonTriggerKey", "MyJobGroup") .WithCronSchedule(noonJobCron) .StartAt(DateTime.UtcNow) .WithPriority(1) .Build(); // 创建第二个触发器(午夜0点) ITrigger midnightTrigger = TriggerBuilder.Create() .WithDescription("MidnightTrigger") .WithIdentity("MidnightTriggerKey", "MyJobGroup") .WithCronSchedule(midnightJobCron) .StartAt(DateTime.UtcNow) .WithPriority(1) .Build(); bool jobExists = await scheduler.CheckExists(job.Key); if (jobExists) { // 如果Job已存在,分别更新两个触发器 await scheduler.RescheduleJob(new TriggerKey("NoonTriggerKey", "MyJobGroup"), noonTrigger); await scheduler.RescheduleJob(new TriggerKey("MidnightTriggerKey", "MyJobGroup"), midnightTrigger); } else { // 首次调度,同时绑定Job和两个触发器 await scheduler.ScheduleJob(job, new List<ITrigger> { noonTrigger, midnightTrigger }, true); } } }
额外注意点
- 避免使用
async static void:这种写法无法被正确捕获异常,也无法等待完成,改成async static Task是更规范的异步写法。 - 触发器和Job的Identity要区分开:不要给触发器和Job用完全相同的Key,否则容易出现冲突或混淆。
- 尽量用
await替代.Result/.Wait():后者会导致线程阻塞,容易引发死锁问题,异步代码里优先使用await。
内容的提问来源于stack exchange,提问作者sridharnetha
相关产品推荐
相关产品推荐

