因为项目中需要每月/每天建表,每天进行一些统计,所以封装了一个类库进行使用。
一、使用说明:
1. 把要执行的任务新建一个类放到本Web项目中,可以放在任意位置,建议放在AutoTask 文件夹下 2. 对该类应用属性 AutoTask 如下所示 [AutoTask(EnterMethod = "StartTask", IntervalSeconds = 86400, StartTime = "2016-12-28 00:00:00")] 说明:EnterMethod 是任务入口,IntervalSeconds 是执行间隔,StartTime 是开始执行时间 如果设置IntervalSeconds 为空或0 ,则该任务只启动时执行一次,忽略后面的start Time 参数 如果没有设置StartTime ,则该任务启动时立刻开始执行,按照间隔时间,每隔IntervalSeconds 秒执行一次。 如果StartTime 大于当前日期,则任务从StartTime 开始执行。 如果StartTime 小于当前日期,则从 StartTime + IntervalSecondes*n 开始执行,n为使该表达式大于DateTime.Now 的最小值。 3. 由此可以实现所有的定时功能。 如指定 每小时执行,则设置IntervalSeconds=3600,每天执行则设置IntervalSeconds=86400 若设置每天 0 点执行,则可以设置StartTime = "xxxx-xx-xx 00:00:00",IntervalSeconds=86400 若设置每周二晚上23 点执行 ,则可以设置StartTime = "xxxx-xx-xx 23:00:00",IntervalSeconds=604800 //86400*7 ,xxxx-xx-xx 可以设置为以前一个周二的日期 若设置每月,每年指定日期,则可以设置每天执行,然后在执行的代码里进行判断,判断日期是否是指定的日期,为保证易用性,本类库不进行扩展
二、源码说明:
1. 在Global.asax.cs Application_Start中添加如下代码
AutoTaskAttribute.RegisterTask();
添加Application_End 方法,解决IIS应用程序池自动回收的问题
protected void Application_End(object sender, EventArgs e) { //下面的代码是关键,可解决IIS应用程序池自动回收的问题 Thread.Sleep(1000); //这里设置你的web地址,可以随便指向你的任意一个aspx页面甚至不存在的页面,目的是要激发Application_Start
//我这里是一个验证token的地址。 string url = System.Configuration.ConfigurationManager.AppSettings["tokenurl"]; HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url); HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse(); Stream receiveStream = myHttpWebResponse.GetResponseStream();//得到回写的字节流 }
2. 把该类文件添加到项目中
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading.Tasks; using System.Web; using WebMVC.Utils; namespace WebMVC.Filters { /// <summary> /// Author:BigLiang(lmw) /// Date:2016-12-29 /// </summary> [AttributeUsage(AttributeTargets.Class)] public class AutoTaskAttribute : Attribute { /// <summary> /// 入口程序 /// </summary> public string EnterMethod { get; set; } /// <summary> /// 执行间隔秒数(未设置或0 则只执行一次) /// </summary> public int IntervalSeconds { get; set; } /// <summary> /// 开始执行日期 /// </summary> public string StartTime { get; set; } //保留对Timer 的引用,避免回收 private static Dictionary<AutoTaskAttribute, System.Threading.Timer> timers = new Dictionary<AutoTaskAttribute, System.Threading.Timer>(); /// <summary> /// Global.asax.cs 中调用 /// </summary> public static void RegisterTask() { new Task(() => StartAutoTask()).Start(); } /// <summary> /// 启动定时任务 /// </summary> private static void StartAutoTask() { var types = Assembly.GetExecutingAssembly().ExportedTypes.Where(t => Attribute.IsDefined(t, typeof(AutoTaskAttribute))).ToList(); foreach (var t in types) { try { var att = (AutoTaskAttribute)Attribute.GetCustomAttribute(t, typeof(AutoTaskAttribute)); if (att != null) { if (string.IsNullOrWhiteSpace(att.EnterMethod)) { throw new Exception("未指定任务入口!EnterMethod"); } var ins = Activator.CreateInstance(t); var method = t.GetMethod(att.EnterMethod); if (att.IntervalSeconds > 0) { int duetime = 0; //计算延时时间 if (string.IsNullOrWhiteSpace(att.StartTime)) { duetime = 1000; } else { var datetime = DateTime.Parse(att.StartTime); if (DateTime.Now <= datetime) { duetime = (int)(datetime - DateTime.Now).TotalSeconds * 1000; } else { duetime = att.IntervalSeconds * 1000 - ((int)(DateTime.Now - datetime).TotalMilliseconds) % (att.IntervalSeconds * 1000); } } timers.Add(att,new System.Threading.Timer((o) => { method.Invoke(ins, null); }, ins, duetime, att.IntervalSeconds * 1000)); } else { method.Invoke(ins, null); } } } catch (Exception ex) { //LogHelper.Error(t.FullName + " 任务启动失败", ex); } } } } }
3. 使用示例
/// <summary> /// 测试任务,每10分钟执行一次 /// </summary> [AutoTask(EnterMethod = "StartTask", IntervalSeconds = 600, StartTime = "2016-12-28 10:45:00")] public class TestTask { /// <summary> ////// </summary> public static void StartTask() { LogHelper.Info("定时任务启动成功!"); LogHelper.Info("定时任务执行完毕!"); } }
这是我的框架中关于定时任务的一块,以后会把整个框架分享出来。