工作中需要做個每天定時發郵件的功能,了解之后知道java里有做定時任務比較容易的方法,就是Quartz,在C#里叫Quartz.Net。
在寫代碼之前需要引用幾個dll文件,分別是C5.dll、Common.Logging.dll和Quartz.dll;還有一個QuartzManager.cs文件,直接復制到項目中
QuartzManager.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Quartz; using Quartz.Impl; using Quartz.Impl.Triggers; namespace Quartz { public static class QuartzManager { private static ISchedulerFactory sf = null; private static IScheduler sched = null; static QuartzManager() { sf = new StdSchedulerFactory(); sched = sf.GetScheduler(); sched.Start(); } /// <summary> /// 添加Job 並且以定點的形式運行 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="JobName"></param> /// <param name="CronTime"></param> /// <param name="jobDataMap"></param> /// <returns></returns> public static DateTimeOffset AddJob<T>(string JobName, string CronTime, string jobData) where T : IJob { IJobDetail jobCheck = JobBuilder.Create<T>().WithIdentity(JobName, JobName + "_Group").UsingJobData("jobData", jobData).Build(); ICronTrigger CronTrigger = new CronTriggerImpl(JobName + "_CronTrigger", JobName + "_TriggerGroup", CronTime); return sched.ScheduleJob(jobCheck, CronTrigger); } /// <summary> /// 添加Job 並且以定點的形式運行 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="JobName"></param> /// <param name="CronTime"></param> /// <returns></returns> public static DateTimeOffset AddJob<T>(string JobName, string CronTime) where T : IJob { return AddJob<T>(JobName, CronTime, null); } /// <summary> /// 添加Job 並且以周期的形式運行 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="JobName"></param> /// <param name="SimpleTime">毫秒數</param> /// <returns></returns> public static DateTimeOffset AddJob<T>(string JobName, int SimpleTime) where T : IJob { return AddJob<T>(JobName, DateTime.UtcNow.AddMilliseconds(1), TimeSpan.FromMilliseconds(SimpleTime)); } /// <summary> /// 添加Job 並且以周期的形式運行 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="JobName"></param> /// <param name="SimpleTime">毫秒數</param> /// <returns></returns> public static DateTimeOffset AddJob<T>(string JobName, DateTimeOffset StartTime, int SimpleTime) where T : IJob { return AddJob<T>(JobName, StartTime, TimeSpan.FromMilliseconds(SimpleTime)); } /// <summary> /// 添加Job 並且以周期的形式運行 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="JobName"></param> /// <param name="SimpleTime"></param> /// <returns></returns> public static DateTimeOffset AddJob<T>(string JobName, DateTimeOffset StartTime, TimeSpan SimpleTime) where T : IJob { return AddJob<T>(JobName, StartTime, SimpleTime, new Dictionary<string, object>()); } /// <summary> /// 添加Job 並且以周期的形式運行 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="JobName"></param> /// <param name="StartTime"></param> /// <param name="SimpleTime">毫秒數</param> /// <param name="jobDataMap"></param> /// <returns></returns> public static DateTimeOffset AddJob<T>(string JobName, DateTimeOffset StartTime, int SimpleTime, string MapKey, object MapValue) where T : IJob { Dictionary<string, object> map = new Dictionary<string, object>(); map.Add(MapKey, MapValue); return AddJob<T>(JobName, StartTime, TimeSpan.FromMilliseconds(SimpleTime), map); } /// <summary> /// 添加Job 並且以周期的形式運行 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="JobName"></param> /// <param name="StartTime"></param> /// <param name="SimpleTime"></param> /// <param name="jobDataMap"></param> /// <returns></returns> public static DateTimeOffset AddJob<T>(string JobName, DateTimeOffset StartTime, TimeSpan SimpleTime, Dictionary<string, object> map) where T : IJob { IJobDetail jobCheck = JobBuilder.Create<T>().WithIdentity(JobName, JobName + "_Group").Build(); jobCheck.JobDataMap.PutAll(map); ISimpleTrigger triggerCheck = new SimpleTriggerImpl(JobName + "_SimpleTrigger", JobName + "_TriggerGroup", StartTime, null, SimpleTriggerImpl.RepeatIndefinitely, SimpleTime); return sched.ScheduleJob(jobCheck, triggerCheck); } /// <summary> /// 修改觸發器時間,需要job名,以及修改結果 /// CronTriggerImpl類型觸發器 /// </summary> public static void UpdateTime(string jobName, string CronTime) { TriggerKey TKey = new TriggerKey(jobName + "_CronTrigger", jobName + "_TriggerGroup"); CronTriggerImpl cti = sched.GetTrigger(TKey) as CronTriggerImpl; cti.CronExpression = new CronExpression(CronTime); sched.RescheduleJob(TKey, cti); } /// <summary> /// 修改觸發器時間,需要job名,以及修改結果 /// SimpleTriggerImpl類型觸發器 /// </summary> /// <param name="jobName"></param> /// <param name="SimpleTime">分鍾數</param> public static void UpdateTime(string jobName, int SimpleTime) { UpdateTime(jobName, TimeSpan.FromMinutes(SimpleTime)); } /// <summary> /// 修改觸發器時間,需要job名,以及修改結果 /// SimpleTriggerImpl類型觸發器 /// </summary> public static void UpdateTime(string jobName, TimeSpan SimpleTime) { TriggerKey TKey = new TriggerKey(jobName + "_SimpleTrigger", jobName + "_TriggerGroup"); SimpleTriggerImpl sti = sched.GetTrigger(TKey) as SimpleTriggerImpl; sti.RepeatInterval = SimpleTime; sched.RescheduleJob(TKey, sti); } /// <summary> /// 暫停所有Job /// 暫停功能Quartz提供有很多,以后可擴充 /// </summary> public static void PauseAll() { sched.PauseAll(); } /// <summary> /// 恢復所有Job /// 恢復功能Quartz提供有很多,以后可擴充 /// </summary> public static void ResumeAll() { sched.ResumeAll(); } /// <summary> /// 刪除Job /// 刪除功能Quartz提供有很多,以后可擴充 /// </summary> /// <param name="JobName"></param> public static void DeleteJob(string JobName) { JobKey jk = new JobKey(JobName, JobName + "_Group"); sched.DeleteJob(jk); } /// <summary> /// 卸載定時器 /// </summary> /// <param name="waitForJobsToComplete">是否等待job執行完成</param> public static void Shutdown(bool waitForJobsToComplete) { sched.Shutdown(waitForJobsToComplete); } } }
窗體界面上只有一個Button按鈕,點擊之后將當前Windows窗體關閉,而我的定時任務就是實現這個關閉。
.closeForm();關閉窗體方法在另寫的一個stopjob.cs類文件調用 這個類需要繼承IJob
using Quartz; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace winform狀態欄 { [PersistJobDataAfterExecution] [DisallowConcurrentExecution] public class stopjob : IJob { public void Execute(IJobExecutionContext context) { Program.form.closeForm(); } } }
上面代碼中,Program.form並不是開始創建的那個窗體,而是在Program類文件中創建的靜態Form。為什么另創建一個靜態Form?涉及到子線程關閉主線程問題
using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; namespace winform狀態欄 { static class Program { public static Form1 form; /// <summary> /// 應用程序的主入口點。 /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); form = new Form1(); Application.Run(form); } } }
Form.cs文件里引用Quartz(using Quartz;)
然后是關閉按鈕(Button)的事件
using Quartz; using System; using System.Text.RegularExpressions; using System.Windows.Forms; namespace winform狀態欄 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button_close(object sender, EventArgs e) { //cron表達式 參考 http://www.cnblogs.com/sunjie9606/archive/2012/03/15/2397626.html QuartzManager.AddJob<stopjob>("每隔5秒", "*/5 * * * * ?");//每隔5秒執行一次這個方法 } private delegate void CloseForm();//設計到多線程,子線程去控制主線程的控件,InvokeRequired值為true,用到定義委托,使得這個控制行為成為主線程的行為 public void closeForm() { if (this.InvokeRequired) { this.BeginInvoke(new CloseForm(closeForm)); } else { this.Close(); } } } }
關於執行stopjob的時間,我這里是用的每隔5秒執行一次,具體的解釋在另一位博主那里有介紹
http://www.cnblogs.com/sunjie9606/archive/2012/03/15/2397626.html
其中C5.dll、Common.Logging.dll、Quartz.dll文件的鏈接http://pan.baidu.com/s/1hsBn1Bm(如果失效聯系博主)
我學習Quartz.Net時用的是winform,大家可以試試別的,這樣關於線程的問題應該就可以避免,這也是我沒有想到的問題