Quartz.Net是一个从java版的Quartz移植过来的定时任务框架,可以实现异常灵活的定时任务,开发人员只要编写少量的代码就可以实现“每隔1小时执行”,“每天22点执行”,
“每月18日的下午执行8次”等各种定时任务。
Quartz.Net的基本概念:
Quartz.Net中的概念:计划者(IScheduler),工作(IJob),触发器(Trigger)。
总结是就是:给计划者一个工作,让它在Trigger(什么条件下做这件事)触发的条件下执行这个工作(IJob)
将要定时执行的任务的代码写到实现IJob 接口的Execute 方法中即可,时间到来的时候Execute方法会被调用。
使用方法:
安装Quartz.Net (因为版本变化太大,前后可能不兼容,因此这边建议安装 2.5.0版本)
去Nuget程序包中搜索Quartz.net安装,或者执行: Install-Package Quartz -Version 2.5.0
Install-Package Quartz -Version 2.5.0
第一步:在项目中创建一个类(我取名叫MyQuartz),这个类继承自Quartz.Net 的IJob接口
using System; namespace MvcApp { using Quartz; using System.IO; using System.Web.Hosting; /// <summary> /// 创建一个定时任务执行任务的MyQuartz类,这个类必须继承自IJob /// </summary> public class MyQuartz : IJob { public void Execute(IJobExecutionContext context) { //注意点:比如我设置了一年每月都执行一次任务代码,那遇到春节不需要执行怎么办呢?难道春节的时候要把项目停下来修改下代码,然后再发布? 答案是当然不需要。该怎么执行依然怎么执行,我们只需要在这里设置一下就可以了 //例如在Execute方法的最上面做一个判断:如果当前月是春节,直接return。哈哈,是不是很灵活 try { //我们需要定时任务执行的代码都写在这个Execute方法里 File.AppendAllText("d://a.txt", "*****" + DateTime.Now.ToString() + "******"); //注意点1:使用Quartz执行定时任务的时候,有个容易出错的点,就是在我们使用HttpContext类 //当我们HttpContext.Current.Server.MapPath("~/Web.Config") 来获取某个文件的物理路径的时候 //容易报空引用这个错误,因为使用Quartz执行定时任务的时候Execute方法是在单独的线程中被执行的 //而我们的这个HttpContext.Current只能在外部的处理线程中我们才能用,所以它为null。所以就报空引用了 //那这个问题我们怎么解决呢?我们可以用另外一个类来替代 //var path = HostingEnvironment.MapPath("~/Web.Config"); //注意点2 //IJob的Execute中异常问题:由于Job是运行在单独的线程中的,以你次如果Execute中如果发生异常,调试的时候也不会断点暂停的,就好像什么也没有发生过一样,如果运行在Asp.net中,也不会触发Asp.net的“未处理异常处理程序”就好像没有执行一样。为了当出现异常的时候我们能及时发现,就需要把Execute的代码用try..Catch包裹起来。然后把异常处理(比如记录到日志) } catch (Exception ex) { File.AppendAllText("d://log.txt", "程序报错啦:" + ex.Message); } } } }
第二布:配置
我选择在MVC项目的App_Start文件夹中创建一个QuartzConfig.cs类,将配置文件写在这里(你们可以选择你们觉得合适的地方,只要能执行到这个配置文件代码就行)
using System; namespace MvcApp.App_Start { using Quartz; using Quartz.Impl; using Quartz.Spi; public class QuartzConfig { public static void RunProgramRunExample() { //创建一个任务的安排者(调度者) IScheduler sched = new StdSchedulerFactory().GetScheduler(); //--------------任务1 //创建一个任务, //第一个参数:表示任务名称,我这里取名叫“RenWuNameA”,它必须是唯一的 //第二个参数:表示需要定时执行任务的这个类的类名(这个类必须实现了IJob接口的) JobDetailImpl jbBossReport = new JobDetailImpl("RenWuNameA", typeof(MyQuartz)); //创建一个任务的执行条件(Trigger)例如:在什么时候执行这个任务,在几点几时执行这个任务。 //AtHourAndMinuteOnGivenDaysOfWeek 表示每天执行 //我这里设置在每天的的23:45分执行 //第一个参数:表示小时 //第二个参数:表示分钟 IMutableTrigger triggerBossReport = CronScheduleBuilder.DailyAtHourAndMinute(0, 47).Build();//表示在每天的23:45分执行 /* //AtHourAndMinuteOnGivenDaysOfWeek 表示在可多选的周几周几执行(可多选) //我这里设置在每周六和每周日的13:55分执行 //第一个参数:表示小时 //第二个参数:表示分钟 //第三个参数:是一个可变数组,是一个DayOfWeek类型的枚举,可选周一,周二,周三,周四,周五,周六,周日) var triggerBossReport2 = CronScheduleBuilder.AtHourAndMinuteOnGivenDaysOfWeek(13, 55, DayOfWeek.Saturday, DayOfWeek.Sunday).Build(); */ /* //WeeklyOnDayAndHourAndMinute表示每周固定时间执行: //我这里设置每周五的10:25分执行 //第一个参数:是一个DayOfWeek类型的枚举,可选周一,周二,周三,周四,周五,周六,周日 //第二个参数:小时 //第三个参数:分钟 var triggerBossReport3 = CronScheduleBuilder.WeeklyOnDayAndHourAndMinute(DayOfWeek.Friday, 10, 25).Build(); */ /* //MonthlyOnDayAndHourAndMinute表示每月月固定时间执行 //我这里设置每月的第25天的9:30 分执行 var triggerBossReport4 = CronScheduleBuilder.MonthlyOnDayAndHourAndMinute(25, 9, 30); */ /* //这里我设置每3秒执行一次 CalendarIntervalScheduleBuilder builder = CalendarIntervalScheduleBuilder.Create(); //WithInterval方法有2个参数 //第二个参数:表示时间刻度,如年,月,周,日,时,分,秒,毫秒(它是一个枚举) //第一个参数:表示根据第二个参数选择的时间刻度,执行的次数 builder.WithInterval(3, IntervalUnit.Second); var triggerBossReport = builder.Build(); */ /* //我们还可以使用cron表达式来指定时间执行。 //了解cron表达式:http://www.cnblogs.com/junrong624/p/4239517.html //"0 0 10,14,16 * * ?"就是表达式,表示每天上午10点,下午2点,下午4点执行 var triggerBossReport5 = CronScheduleBuilder.CronSchedule("0 0 10,14,16 * * ?").Build(); */ //表示每隔5秒执行一次 //"*/5 * * * * ?" 表达式就表示每隔五秒执行一次 //var triggerBossReport = CronScheduleBuilder.CronSchedule("*/5 * * * * ?").Build(); //设置这个执行条件的Key。我这里将它取名为triggerTest,名字要保证唯一 triggerBossReport.Key = new TriggerKey("triggerTest"); //将给定的“任务”添加到调度程序中,并关联给定的“执行条件” sched.ScheduleJob(jbBossReport, triggerBossReport); //------------------任务2 JobDetailImpl jR2 = new JobDetailImpl("RenWuNameB", typeof(MyQuartz)); var tBR2 = CronScheduleBuilder.AtHourAndMinuteOnGivenDaysOfWeek(13, 55, DayOfWeek.Saturday, DayOfWeek.Sunday).Build(); tBR2.Key = new TriggerKey("tT2"); sched.ScheduleJob(jR2, tBR2); //启动 sched.Start(); } } }
配置好后,我们在程序启动的时候调用它,所以我选择了在Global.asax中调用执行这个配置文件
namespace MvcApp { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); //调用定时任务 QuartzConfig.RunProgramRunExample(); } } }