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();
}
}
}
}