香港那边公司的市场部开会时要求我们这边实现一个定时发送邮件的功能,即在每天下午5点左右定时把今天已通过三审的订单信息发给市场部的经理,告诉他哪些订单已经通过了终审。平时只知道如何用.net发送邮件,但不知如何定时发送邮件。于是百度了一下,总结起来有以下那么三种:
(1)做一个winform 来定时发邮件。然后通过windows计划任务,设置为指定时间,每次自动运行,运行完毕后自动关闭。
(2)用sqlserver 数据库实现发邮件,用sqlserver实现发邮件的存储过程,然后制定一个作业,制定时间运行。
(3)在 Global.asax 文件里编程。事件:Application_Start。利用Time类编程。比如服务器1秒钟执行一次判断。
香港那边的公司的ERP糸统是BS模式,由于对方公司服务器环境条件的限制,我和我师傅决定用第三种方法。在编程之前,先介绍一下Global.asax文件里的几个方法。
|
下面是具体的做法:
代码
|
1
2 protected override void OnStart(string[] args)
3 {
4 MyTimer();
5 }
6
7 //实例化System.Timers.Timer
8 private void MyTimer()
9 {
10 //设置时间间隔
11 System.Timers.Timer MT = new System.Timers.Timer(int.Parse(ConfigResource.Interval)*60*1000);
12 MT.Elapsed += new System.Timers.ElapsedEventHandler(MTimedEvent);
13 MT.Enabled = true;
14
15 }
16 //构造System.Timers.Timer实例 间隔时间事件 (定时执行事件)
17 private void MTimedEvent(object source, System.Timers.ElapsedEventArgs e)
18 {
19 //开始工作
20 StartWork();
21 }
22
23 public void StartWork()
24 {
25 //从数据库DB查询表A中的时间 代码省略。。。
26 //时间比较
27 if() //时间大于当前系统时间
28 {
29 //发送邮件
30 int iStatus = SendMail("你指定的收件人Email地址","标题","内容");
31 if( iStatus > 0)
32 {
33 using (StreamWriter sw = new StreamWriter(filePath + "log.txt", System.Text.Encoding.GetEncoding("utf-8")))
34 {
35 sw.Wirte(System.DateTime.Now.ToString() + " 发送邮件成功!")
36 }
37 }
38 else{//失败}
39 }
40 }
41
42 /// <summary>
43 /// 发送EMAIL
44 /// </summary>
45 /// <param name="sRecipientEmail">收件人地址</param>
46 /// <param name="sSubject">主题</param>
47 /// <param name="sMessage">内容</param>
48 /// <returns>发送是否成功</returns>
49 public bool SendMail(string sRecipientEmail, string sSubject, string sMessage)
50 {
51
52 //邮件对象
53 MailMessage emailMessage;
54
55 //smtp客户端对象
56
57 SmtpClient client;
58
59 // 初始化邮件对象
60
61 String sSenderEmail = "你的邮箱";
62
63 emailMessage = new MailMessage(sSenderEmail, sRecipientEmail, sSubject, sMessage);
64 emailMessage.IsBodyHtml = true;
65 emailMessage.SubjectEncoding = System.Text.Encoding.Default;
66 emailMessage.BodyEncoding = System.Text.Encoding.Default;
67 //加入
68 emailMessage.Headers.Add("X-Priority", "3");
69 emailMessage.Headers.Add("X-MSMail-Priority", "Normal");
70 emailMessage.Headers.Add("X-Mailer", "Microsoft Outlook Express 6.00.2900.2869");
71 emailMessage.Headers.Add("X-MimeOLE", "Produced By Microsoft MimeOLE V6.00.2900.2869");
72
73 //邮件发送客户端
74 client = new SmtpClient();
75
76 //邮件服务器及帐户信息
77 client.Host = "邮件服务器";
78 //client.Host = "smtp.163.com";
79
80 //client.Port = 465;
81 //client.EnableSsl = true;
82 System.Net.NetworkCredential Credential = new System.Net.NetworkCredential();
83
84 Credential.UserName = "你的邮箱帐号" //可以在资源文件中配置
85 Credential.Password = "密码"
86
87 client.Credentials = Credential;
88
89 try
90 {
91 client.Send(emailMessage);
92 }
93 catch (Exception e)
94 {
95 return false;
96 }
97 return true;
98
99 }
100
101
102
asp.net程序一般是当用户请求一个Page,或者请求一个WebService的时候,才会执行一段代码,如果我们希望让程序定时自动执行代码,但是又不增加新的应用程序,应该怎么做呢?
首先,给你的web应用程序,添加一个“Global.asax”文件,这个类里面默认有一个“Application_Start”,我们就在这个方法里面添加定时程序的逻辑代码。这样,只要有一个人访问了这个web应用,就会启动这个定时程序。
为了方便我们对定时程序的管理,我们单独编写一个类,专门用于控制定时程序。这个类中用的核心对象是System.Timers.Timer。下面说一下这个类设计的基本思路:ExecuteTask是一个公共的事件对象,以后调用者可以利用它来添加回调函数。_task是这个类型的唯一静态实例,调用者可以用Instance()方法读取它。_timer就是实现定时运行的对象,Interval是运行的间隔时间。
public class Time_Task
{
public event System.Timers.ElapsedEventHandler ExecuteTask;
private static readonly Time_Task _task = null;
private System.Timers.Timer _timer = null;
private int _interval = 1000;
public int Interval
{
set
{
_interval = ;
}
get
{
return _interval;
}
}
static Time_Task()
{
_task = new Time_Task();
}
public static Time_Task Instance()
{
return _task;
}
public void Start()
{
if(_timer == null)
{
_timer = new System.Timers.Timer(_interval);
_timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);
_timer.Enabled = true;
_timer.Start();
}
}
protected void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if(null != ExecuteTask)
{
ExecuteTask(sender, e);
}
}
public void Stop()
{
if(_timer != null)
{
_timer.Stop();
_timer.Dispose();
_timer = null;
}
}
}
有了这个类型,我们可以在Application_Start方法中轻松的实现定时了。
protected void Application_Start(object sender, EventArgs e)
{
Time_Task.Instance().ExecuteTask += new System.Timers.ElapsedEventHandler(Global_ExecuteTask);
Time_Task.Instance().Interval = 1000 * 60;//表示间隔1分钟
Time_Task.Instance().Start();
}
void Global_ExecuteTask(object sender, System.Timers.ElapsedEventArgs e)
{
//在这里编写需要定时执行的逻辑代码
}
需要注意的是,当你重新部署web应用的时候,比如更新了DLL文件,或者修改了web.config文件,就会中止这个定时程序,需要有人再次请求Page,才能把它启动起来。
定时执行。。。。在webform中实现真的有点别扭,会因各种因素而停止执行,比如
1:web服务停止了一段时间内没人访问;
2:莫名其妙的不执行;
3:……
所以,95%有经验的人会选择使用webservice+客户端的方式来实现。
而我这里介绍的偏偏是使用纯Global.asax实现。
前提,我要实现的是定时处理数据库里的过期信息,比如业务员跟踪的业务到期释放、一个月未登录的用户自动锁定等等。
备注:要是需要实现定时对外发信之类的功能就不合适了,为什么呢?因为所谓定时收信的时间参照是外界的,即便你的站点"死"了,时间依然在走,那么此时一旦到了时间而你的站点处理“死”的状态,必然就收不到信了。而处理系统内的业务数据就不一样了,假设你的站点是“死”的,又何来业务?有业务的前提是:站点是正常的。说到这你明白了一些吗?
扯远了,下面就说说具体步骤吧:
第一步,打开Web.config,在appSettings下新建
这个value自己随时可以改,主要是控制任务执行的权限
第二步,新建Global.asax,打开Global.asax.cs
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using System.Timers;
namespace CGWCS.WebFile
{
public class Global : System.Web.HttpApplication
{
public static HttpContext myContext = HttpContext.Current;
protected void Application_Start(object sender, EventArgs e)
{
System.Timers.Timer aTimer = new System.Timers.Timer();
aTimer.Elapsed += new ElapsedEventHandler(TimeEvent);
aTimer.Interval = 1000;// 设置引发时间的时间间隔 此处设置为1秒
aTimer.Enabled = true;
}
private void TimeEvent(object source, ElapsedEventArgs e)
{
// 得到 hour minute second 如果等于某个值就开始执行某个程序。
int intHour = e.SignalTime.Hour;
int intMinute = e.SignalTime.Minute;
int intSecond = e.SignalTime.Second;
// 设置 每天的7:30:00开始执行程序
//假设web服务异常或正常的重启,则强行执行一次任务(目的是为防止遗漏)
if ((intHour == 7 && intMinute == 30 && intSecond == 0) || myContext.Application["AutoTask_1"] == null)
{
string _url = ServerUrl() + "/autotask.aspx?oper=Release1&password=" + System.Configuration.ConfigurationManager.AppSettings["AutoTask:Password"];
System.IO.StreamWriter sw = new System.IO.StreamWriter(myContext.Request.PhysicalApplicationPath + "\\log.txt", true, System.Text.Encoding.UTF8);
sw.WriteLine(e.SignalTime.ToString());
sw.WriteLine(GetHttpPage(_url));
sw.Close();
sw.Dispose();
myContext.Application.Lock();
myContext.Application["AutoTask_1"] = "true";
myContext.Application.UnLock();
}
// 设置 每天的7:45:00开始执行程序
//假设web服务异常或正常的重启,则强行执行一次任务(目的是为防止遗漏)
if ((intHour == 7 && intMinute == 45 && intSecond == 0) || myContext.Application["AutoTask_2"] == null)
{
string _url = ServerUrl() + "/autotask.aspx?oper=Release2&password=" + System.Configuration.ConfigurationManager.AppSettings["AutoTask:Password"];
System.IO.StreamWriter sw = new System.IO.StreamWriter(myContext.Request.PhysicalApplicationPath + "\\log.txt", true, System.Text.Encoding.UTF8);
sw.WriteLine(e.SignalTime.ToString());
sw.WriteLine(GetHttpPage(_url));
sw.Close();
sw.Dispose();
myContext.Application.Lock();
myContext.Application["AutoTask_2"] = "true";
myContext.Application.UnLock();
}
}
private string ServerUrl()
{
if (myContext.Request.Url.Port == 80)
return "http://" + myContext.Request.Url.Host;
else
return "http://" + myContext.Request.Url.Host + ":" + myContext.Request.Url.Port;
}
private string AppPath()
{
string _ApplicationPath = myContext.Request.ApplicationPath;
if (_ApplicationPath != "/")
_ApplicationPath += "/";
return _ApplicationPath;
}
private string GetHttpPage(string url)
{
string strResult = string.Empty;
try
{
System.Net.WebClient MyWebClient = new System.Net.WebClient();
MyWebClient.Credentials = System.Net.CredentialCache.DefaultCredentials;
MyWebClient.Encoding = System.Text.Encoding.UTF8;
strResult = MyWebClient.DownloadString(url);
}
catch (Exception)
{
strResult = "页面获取失败";
}
return strResult;
}
protected void Session_Start(object sender, EventArgs e)
{
}
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)
{
}
protected void Application_End(object sender, EventArgs e)
{
}
}
}
第三步:新建一个autotask.aspx,打开autotask.aspx.cs
using System;
using System.Data;
using System.Web;
namespace CGWCS.WebFile
{
public partial class _autotask : CGWCS.UI.BasicPage
{
private string _operType = string.Empty;
private string _response = string.Empty;
protected void Page_Load(object sender, EventArgs e)
{
this._operType = q("oper");
switch (this._operType)
{
case "Release1":
Release1();
break;
case "Release2":
Release2();
break;
default:
DefaultResponse();
break;
}
Response.Write(this._response);
}
private void DefaultResponse()
{
this._response = "未知操作";
}
private void Release1()
{
string _password = q("password");
if (_password != System.Configuration.ConfigurationManager.AppSettings["AutoTask:Password"])
{
this._response = "密码错误";
return;
}
....这是释放代码
int _doCount = 释放的个数;
if (_doCount > 0)
{
this._response = "成功释放" + _doCount + "个锁定的企业";
}
else
this._response = "没有可以释放的锁定的企业";
}
private void Release2()
{
string _password = q("password");
if (_password != System.Configuration.ConfigurationManager.AppSettings["AutoTask:Password"])
{
this._response = "密码错误";
return;
}
....这是锁定代码
int _doCount = 锁定的用户数;
if (_doCount > 0)
{
this._response = "成功锁定" + _doCount + "个用户";
}
else
this._response = "没有可以锁定的用户";
}
}
}
最后说明一下,虽然编译通过,但是在Global.asax.cs里有些代码是不生效的,比如:
1、不能直接使用HttpContext.Current,需要先定义一个静态值。
2、Request.ServerVariables["Server_Port"].ToString() 和 Request.Url.Port 同时表示当前web服务端口号,但是只能用后者而不能用前者.