在业务复杂的应用程序中,有时候会要求一个或者多个任务在一定的时间或者一定的时间间隔内计划进行,比如定时备份或同步数据库,定时发送电子邮件等,我们称之为计划任务。实现计划任务的方法也有很多,可以采用SQLAgent执行存储过程来实现,也可以采用Windows任务调度程序来实现,也可以使用Windows服务来完成我们的计划任务,这些方法都是很好的解决方案。但是,对于Web应用程序来说,这些方法实现起来并不是很简单的,主机服务提供商或者不能直接提供这样的服务,或者需要你支付许多额外的费用。 本文就介绍一个直接在Web应用程序中使用的简单的方法,这个方法不需要任何额外的配置即可轻松实现。
由于ASP.NET站点是作为Web应用程序运行的,它并不受线程的限制,因此我们可以非常方便地在Application_Start和Application_End事件中建立和销毁一个计划任务。
ASP.NET 框架应用程序在第一次向服务器发出请求时创建,在此之前,不执行 ASP.NET 代码。当第一个请求发出后,将创建一个 HttpApplication 实例池并引发 Application_Start 事件。
HttpApplication 实例处理该请求以及后面的请求,直到最后一个实例退出并引发 Application_End 事件。
IIS应用池回收造成Application_Start中定时执行程序停止的问题的解决方法
原理就是在应用程序结束时发出一个Web请求访问网站,启动Application_Start。
{
// 在应用程序关闭时运行的代码
// 解决应用池回收问题
System.Threading.Thread.Sleep( 5000 );
string strUrl = " 网站地址 " ;
System.Net.HttpWebRequest _HttpWebRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(strUrl);
System.Net.HttpWebResponse _HttpWebResponse = (System.Net.HttpWebResponse)_HttpWebRequest.GetResponse();
System.IO.Stream _Stream = _HttpWebResponse.GetResponseStream(); // 得到回写的字节流
}
下面就简单介绍一下在Web站点实现计划任务的方法。我们的例子是定时往文件里添加信息,作为例子,这里把当前的时间定时地写入文件中。
一个计划任务的工作单元称之为一个任务(Job),下面的代码描述了对所有任务都可以被调度引擎计划执行的一个通用的接口,这里的每个任务实现了Execute方法,供调度引擎进行调用:
public interface ISchedulerJob
{
void Execute();
}
如前所述,我们的例子是实现往文件写如字符日期,下面就是实现这一任务的方法:
{
public void Execute()
{
// 文件保存的物理路径,CSTest为虚拟目录名称,F:\Inetpub\wwwroot\CSTest为物理路径
string p = @" F:\Inetpub\wwwroot\CSTest " ;
// 我们在虚拟目录的根目录下建立SchedulerJob文件夹,并设置权限为匿名可修改,
// SchedulerJob.txt就是我们所写的文件
string FILE_NAME = p + " \\SchedulerJob\\SchedulerJob.txt " ;
// 取得当前服务器时间,并转换成字符串
string c = System.DateTime.Now.ToString( " yyyy-mm-dd hh:MM:ss " );
// 标记是否是新建文件的标量
bool flag = false ;
// 如果文件不存在,就新建该文件
if ( ! File.Exists(FILE_NAME))
{
flag = true ;
StreamWriter sr = File.CreateText(FILE_NAME);
sr.Close();
}
// 向文件写入内容
StreamWriter x = new StreamWriter(FILE_NAME, true ,System.Text.Encoding.Default);
if (flag) x.Write( " 计划任务测试开始: " );
x.Write( " \r\n " + c);
x.Close();
}
}
接下来,我们建立一个配置对象,告诉调度引擎执行什么任务和执行的时间间隔。
{
// 时间间隔
private int sleepInterval;
// 任务列表
private ArrayList jobs = new ArrayList();
public int SleepInterval { get { return sleepInterval; } }
public ArrayList Jobs { get { return jobs; } }
// 调度配置类的构造函数
public SchedulerConfiguration( int newSleepInterval)
{
sleepInterval = newSleepInterval;
}
}
下面就是调度引擎,定时执行配置对象的任务
{
private SchedulerConfiguration configuration = null ;
public Scheduler(SchedulerConfiguration config)
{
configuration = config;
}
public void Start()
{
while ( true )
{
// 执行每一个任务
foreach (ISchedulerJob job in configuration.Jobs)
{
ThreadStart myThreadDelegate = new ThreadStart(job.Execute);
Thread myThread = new Thread(myThreadDelegate);
myThread.Start();
Thread.Sleep(configuration.SleepInterval);
}
}
}
}
所有的准备工作已经完成,下面就是激活引擎的工作了。为了让我们的任务计划执行,我们在Global.asax.cs文件里的Applicatio_Start和Application_End里进行建立和销毁工作,首先建立一个调度进程运行的线程,我们这里的运行间隔时间为3秒钟。
protected void Application_Start(Object sender, EventArgs e)
{
SchedulerConfiguration config = new SchedulerConfiguration( 1000 * 3 );
config.Jobs.Add( new SampleJob());
Scheduler scheduler = new Scheduler(config);
System.Threading.ThreadStart myThreadStart = new System.Threading.ThreadStart(scheduler.Start);
System.Threading.Thread schedulerThread = new System.Threading.Thread(myThreadStart);
schedulerThread.Start();
}
最后还需要在程序退出时进行销毁:
{
if ( null != schedulerThread)
{
schedulerThread.Abort();
}
}
好了,在VS.NET里建立一个C#的Web应用程序工程,建立TaskScheduler.cs类,并修改相应的Global.asax.cs文件。为了能看到效果,我们再建立一个表单WebForm1.aspx,定时刷新来检查我们所记录的数据:
<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false"
Inherits="CSTest.WebForm1" %>