在C#项目开发中,定时任务是非常常见的需求,比如每天凌晨自动备份数据库、每小时同步一次第三方接口数据、每隔十分钟检查一次服务状态等。原生C#自带的Timer类虽然能实现简单的定时功能,但在面对复杂的调度规则,比如按 cron 表达式调度、任务持久化、集群部署等场景时,就显得力不从心。Quartz.NET是一款功能完善的开源定时调度框架,完美适配C#生态,能够轻松应对各类定时任务需求,下面我们就通过实战案例来学习它的使用方法。

Quartz.NET核心概念
在使用Quartz.NET之前,需要先了解它的三个核心概念,这三个概念是构建定时任务的基础:
- IJob:任务接口,所有需要执行的定时任务都需要实现这个接口,在接口的Execute方法中编写具体的任务逻辑。
- JobDetail:任务详情,用来描述一个具体的任务实例,包含任务的类型、唯一标识、描述等信息,还可以给任务传递自定义参数。
- Trigger:触发器,用来定义任务的执行规则,比如多久执行一次、什么时候开始执行、是否重复执行等,Quartz.NET支持多种类型的触发器,最常用的是SimpleTrigger和CronTrigger。
- Scheduler:调度器,是整个框架的核心控制器,负责管理所有的JobDetail和Trigger,按照触发器的规则调度任务的执行。
环境准备与基础配置
首先我们需要在C#项目中引入Quartz.NET依赖,如果你使用的是.NET Core或者.NET 5及以上版本的项目,可以通过NuGet包管理器安装Quartz包,安装命令如下:
// 在NuGet包管理器控制台执行以下命令安装Quartz Install-Package Quartz
安装完成后,我们先创建一个简单的控制台项目来演示基础使用流程,首先实现一个简单的IJob任务:
using Quartz;
using System;
using System.Threading.Tasks;
// 自定义任务类,实现IJob接口
public class SimpleJob : IJob
{
public async Task Execute(IJobExecutionContext context)
{
// 这里编写具体的任务逻辑,这里示例为输出当前时间
Console.WriteLine($"任务执行时间:{DateTime.Now:yyyy-MM-dd HH:mm:ss}");
await Task.CompletedTask;
}
}
简单定时任务实现
接下来我们创建调度器、任务详情和触发器,将任务运行起来,实现一个每隔5秒执行一次的定时任务:
using Quartz;
using Quartz.Impl;
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
// 1. 创建调度器工厂
ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
// 2. 获取调度器实例
IScheduler scheduler = await schedulerFactory.GetScheduler();
// 3. 开启调度器
await scheduler.Start();
// 4. 创建任务详情,指定任务类型为SimpleJob
IJobDetail jobDetail = JobBuilder.Create<SimpleJob>()
.WithIdentity("simpleJob", "group1") // 设置任务唯一标识和分组
.WithDescription("简单测试任务") // 设置任务描述
.Build();
// 5. 创建简单触发器,每隔5秒执行一次,无限重复
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("simpleTrigger", "group1") // 设置触发器唯一标识和分组
.StartNow() // 立即开始执行
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(5) // 间隔5秒
.RepeatForever()) // 无限重复
.Build();
// 6. 将任务详情和触发器绑定到调度器
await scheduler.ScheduleJob(jobDetail, trigger);
// 保持控制台运行,方便观察任务执行效果
Console.WriteLine("定时任务已启动,按任意键退出");
Console.ReadKey();
// 7. 关闭调度器
await scheduler.Shutdown();
}
}
运行上述代码后,你会看到控制台每隔5秒输出一次当前时间,说明定时任务已经成功运行。
使用Cron表达式实现复杂调度
如果我们需要更复杂的调度规则,比如每天凌晨2点执行、每周一到周五的上午10点执行,就可以使用CronTrigger,它支持cron表达式来定义调度规则。下面我们实现一个每天凌晨2点执行的任务:
using Quartz;
using Quartz.Impl;
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
IScheduler scheduler = await schedulerFactory.GetScheduler();
await scheduler.Start();
IJobDetail jobDetail = JobBuilder.Create<SimpleJob>()
.WithIdentity("cronJob", "group2")
.WithDescription("每天凌晨2点执行的任务")
.Build();
// 创建Cron触发器,cron表达式为 0 0 2 * * ? 表示每天凌晨2点执行
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("cronTrigger", "group2")
.WithCronSchedule("0 0 2 * * ?") // cron表达式,秒 分 时 日 月 周 年(可选)
.Build();
await scheduler.ScheduleJob(jobDetail, trigger);
Console.WriteLine("Cron定时任务已启动,按任意键退出");
Console.ReadKey();
await scheduler.Shutdown();
}
}
常用的cron表达式规则如下:
| 表达式示例 | 含义 |
|---|---|
| 0 0/5 * * * ? | 每隔5分钟执行一次 |
| 0 0 9-18 * * MON-FRI | 周一到周五的9点到18点之间,每小时执行一次 |
| 0 30 10 1 * ? | 每月1号的10点30分执行 |
| 0 0 12 ? * WED | 每周三中午12点执行 |
任务参数传递
在实际开发中,我们常常需要给任务传递一些自定义参数,Quartz.NET支持通过JobDataMap来传递参数,下面演示如何传递和使用参数:
using Quartz;
using System;
using System.Threading.Tasks;
// 带参数的任务类
public class ParamJob : IJob
{
public async Task Execute(IJobExecutionContext context)
{
// 从JobDataMap中获取传递的参数
JobDataMap dataMap = context.JobDetail.JobDataMap;
string taskName = dataMap.GetString("taskName");
int executeCount = dataMap.GetInt("executeCount");
Console.WriteLine($"任务名称:{taskName},执行次数:{executeCount},执行时间:{DateTime.Now:yyyy-MM-dd HH:mm:ss}");
await Task.CompletedTask;
}
}
创建任务时传递参数的代码如下:
using Quartz;
using Quartz.Impl;
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
IScheduler scheduler = await schedulerFactory.GetScheduler();
await scheduler.Start();
// 创建任务详情时传递参数
IJobDetail jobDetail = JobBuilder.Create<ParamJob>()
.WithIdentity("paramJob", "group3")
.UsingJobData("taskName", "数据同步任务") // 传递字符串参数
.UsingJobData("executeCount", 1) // 传递整数参数
.Build();
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("paramTrigger", "group3")
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(10)
.RepeatForever())
.Build();
await scheduler.ScheduleJob(jobDetail, trigger);
Console.WriteLine("带参数的定时任务已启动,按任意键退出");
Console.ReadKey();
await scheduler.Shutdown();
}
}
常见注意事项
在使用Quartz.NET时,有几个需要注意的点:
- 任务类必须是public的,并且有无参构造函数,因为Quartz.NET会通过反射创建任务实例。
- 如果任务执行时间超过了触发器的间隔时间,默认情况下Quartz.NET会等待上一次任务执行完成后再执行下一次,不会并发执行同一个任务实例,如果需要并发执行,可以给任务类添加
[DisallowConcurrentExecution]特性来控制,添加该特性后会禁止并发执行。 - 如果是Web项目中使用Quartz.NET,需要将调度器的生命周期和应用程序的生命周期绑定,避免应用程序重启后调度器被释放。
- 生产环境中如果需要任务持久化或者集群部署,需要配置Quartz.NET使用数据库存储Job和Trigger信息,默认是存储在内存中的,重启后任务信息会丢失。
C#Quartz.NET定时任务定时调度修改时间:2026-07-10 23:39:34