web开发中,总是会需要一些定时任务,比如发email(在前台等email的发送随时准备接受User的雷霆一怒吧),比如每月初发报表给老板们。
Global.asax.cs 的Application_Start 中设置一个System.Timers.Timer,定时执行一个方法就做到了。
但是比较郁闷的问题是,IIS一段时间没有人访问时会回收,System.Timers.Timer也就被回收掉了。
网上搜索,人家的建议是Application_End中重新开一个网页,但是经过试验,发现2个需要注意的地方:
1)一定要睡觉 Thread.Sleep(1000*10); 一定不能少,猜想的原因在注释中。
2)回收问题 之前没睡觉,1个小时IIS就回收了。后来我想在Timer里面增加访问网站(可以在注释中看到) ,但是没注意"计划生育",就不断地增加访问网站的数量,后来也是1个小时左右挂了。加了一个计数功能,发现数量比较大的时候会塞死,后面增加了回收部分。解决了部分问题,再加上"计划生育",Lock和设定Application["Timer"]等。
receiveStream.Close(); myHttpWebResponse.Close(); myHttpWebResponse.Close();
3)最后发现,比较保险的方法是在定时任务中增加一个访问网页的动作,这样Session就一直会保持2个,双保险了。
using System;
using System.IO; using System.Threading; using System.Timers; using System.Web; using System.Web.Caching; namespace WebService { public class Global : System.Web.HttpApplication { object objLock = new object(); protected void Application_Start(object sender, EventArgs e) { StreamWriter sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "log.txt", true); sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":Application_Start"); sw.Close(); //定义定时器 //1000表示1秒的意思 lock (objLock) { if (Application["Timer"] == null) { System.Timers.Timer myTimer = new System.Timers.Timer(1000 * 60); //TaskAction.SetContent 表示要调用的方法 myTimer.Elapsed += new System.Timers.ElapsedEventHandler(TaskAction.SetContent); myTimer.AutoReset = true; myTimer.Enabled = true; Application["Timer"] = myTimer; StreamWriter sw1 = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "log.txt", true); sw1.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":Application_Start Start Timer"); sw1.Close(); } } Application["Count1"] = 0; } protected void Session_Start(object sender, EventArgs e) { Application["Count1"] = (int)Application["Count1"] + 1; Session["Time"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); StreamWriter sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "log.txt", true); sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":Session_Start:" + Session["Time"].ToString() + ":" + Application["Count1"].ToString()); sw.Close(); lock (objLock) { if (Application["Timer"] == null) { System.Timers.Timer myTimer = new System.Timers.Timer(1000 * 60); //TaskAction.SetContent 表示要调用的方法 myTimer.Elapsed += new System.Timers.ElapsedEventHandler(TaskAction.SetContent); myTimer.AutoReset = true; myTimer.Enabled = true; Application["Timer"] = myTimer; sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "log.txt", true); sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":Session_Start Start Timer"); sw.Close(); } } } protected void Application_BeginRequest(object sender, EventArgs e) { } protected void Application_AuthenticateRequest(object sender, EventArgs e) { } protected void Application_Error(object sender, EventArgs e) { } protected void Session_End(object sender, EventArgs e) { Application["Count1"] = (int)Application["Count1"] - 1; if (Session.Contents["Time"] == null) { Session.Contents["Time"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); } StreamWriter sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "log.txt", true); sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":Session_End:" + Session.Contents["Time"].ToString() + ":" + Application["Count1"].ToString()); sw.Close(); lock (objLock) { if (Application["Timer"] == null) { System.Timers.Timer myTimer = new System.Timers.Timer(1000 * 60); //TaskAction.SetContent 表示要调用的方法 myTimer.Elapsed += new System.Timers.ElapsedEventHandler(TaskAction.SetContent); myTimer.AutoReset = true; myTimer.Enabled = true; Application["Timer"] = myTimer; sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "log.txt", true); sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":Session_End Start Timer"); sw.Close(); } } } protected void Application_End(object sender, EventArgs e) { StreamWriter sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "log.txt", true); sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":Application_End:1:" + Application["Count1"].ToString()); sw.Close(); try { //下面的代碼是關鍵,可解決IIS應用程序池自動回收的問題 (原注釋) //猜想原因:空出時間讓IIS清理之後再添加東西進去,避免清理的時候正好碰到訪問網站 // 或者就是想睡睡覺? Thread.Sleep(1000*10); string url = "http://10.40.1.186:456/webform1.aspx"; System.Net.HttpWebRequest myHttpWebRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url); myHttpWebRequest.ServicePoint.Expect100Continue = false; System.Net.HttpWebResponse myHttpWebResponse = (System.Net.HttpWebResponse)myHttpWebRequest.GetResponse(); System.IO.Stream receiveStream = myHttpWebResponse.GetResponseStream();//得到回写的字节流 receiveStream.Close(); myHttpWebResponse.Close(); myHttpWebResponse.Close(); } catch (Exception ex) { StreamWriter sw2 = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "log.txt", true); sw2.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":Application_End Exception:" + ex.ToString()); sw2.Close(); } //sw.WriteLine(receiveStream.ToString()); StreamWriter sw1 = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "log.txt", true); sw1.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":Application_End:2:" + Application["Count1"].ToString()); sw1.Close(); } } public static class TaskAction { /// <summary> /// 定时器委托任务 调用的方法 /// </summary> /// <param name="source"></param> /// <param name="e"></param> public static void SetContent(object source, ElapsedEventArgs e) { try { StreamWriter sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "log.txt", true); sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":Timer Work"); sw.Close(); string url = "http://10.40.1.186:456/webform1.aspx"; System.Net.HttpWebRequest myHttpWebRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url); myHttpWebRequest.ServicePoint.Expect100Continue = false; System.Net.HttpWebResponse myHttpWebResponse = (System.Net.HttpWebResponse)myHttpWebRequest.GetResponse(); System.IO.Stream receiveStream = myHttpWebResponse.GetResponseStream();//得到回写的字节流 receiveStream.Close(); myHttpWebResponse.Close(); myHttpWebResponse.Close(); //sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "log.txt", true); //sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":SetContent END:2"); //sw.Close(); } catch (Exception ex) { StreamWriter sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "log.txt", true); sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":Timer Work Exception:" + ex.ToString()); sw.Close(); } } } }