標籤:ati 執行預存程序 class cti 原因 等等 過程 代碼 ret
在複雜的商務應用程式中,有時候會要求一個或者多個任務在一定的時間或者一定的時間間隔內計划進行,比如定時備份或同步資料庫,定時寄送電子郵件,定期處理使用者狀態資訊,支付系統中定期同步異常賬單等等,我們稱之為計劃任務。
實現計劃任務的方法也有很多,可以採用SQLAgent執行預存程序,採用Windows任務發送器來實現,也可以使用Windows服務來完成我們的計劃任務,這些方法都是不錯的解決方案。但是,以上這些都需要有伺服器的許可權才能進行,而對於虛擬機器主機客戶使用的Web應用程式來說,這些方法實現起來並不是很簡單的,主機服務提供者或者不能直接提供這樣的服務,或者需要你支付許多額外的費用。
看過一些這方面的文章,發現有一個共同的缺點:IIS運行到一定時期,計劃任務就停止了。尋找原因發現是IIS的應用程式集區定期回收導致計劃任務停止。本文的這個方法可以解決應用程式集區回收問題。
using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Net;using System.Threading;using System.Timers;using System.Web;using System.Web.Security;using System.Web.SessionState;namespace TimingTask{ /** *原理:Global.asax 可以是asp.net中應用程式或會話事件處理常式, *我們用到了Application_Start(應用程式開始事件)和Application_End(應用程式結束事件)。 *當應用程式開始時,啟動一個定時器,用來定時執行任務YourTask()方法, *這個方法裡面可以寫上需要調用的邏輯代碼,可以是單線程和多線程。 *當應用程式結束時,如IIS的應用程式集區回收,讓asp.net去訪問當前的這個web地址。 *這裡需要訪問一個aspx頁面,這樣就可以重新啟用應用程式。 */ public class Global : System.Web.HttpApplication { //在應用程式啟動時啟動並執行代碼 protected void Application_Start(object sender, EventArgs e) { //定時器 System.Timers.Timer myTimer = new System.Timers.Timer(2000); myTimer.Elapsed += new ElapsedEventHandler(myTimer_Elapsed); myTimer.Enabled = true; myTimer.AutoReset = true; } private void myTimer_Elapsed(object source, ElapsedEventArgs e) { try { RunTheTask(); } catch (Exception ex) { WebForm1.html = ex.Message; } } private void RunTheTask() { //在這裡寫你需要執行的任務 WebForm1.html = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":AutoTask is Working!"; } // 在新會話啟動時啟動並執行代碼 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) { // 注意: 只有在 Web.config 檔案中的 sessionstate 模式設定為 // InProc 時,才會引發 Session_End 事件。如果會話模式設定為 StateServer // 或 SQLServer,則不會引發該事件 } // 在應用程式關閉時啟動並執行代碼 protected void Application_End(object sender, EventArgs e) { WebForm1.html = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ":Application End!"; //下面的代碼是關鍵,可解決IIS應用程式集區自動回收的問題 Thread.Sleep(1000); //這裡設定你的web地址,可以隨便指向你的任意一個aspx頁面甚至不存在的頁面,目的是要激發Application_Start string url = "WebForm1.aspx"; HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url); HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse(); Stream receiveStream = myHttpWebResponse.GetResponseStream();//得到回寫的位元組流 } }}
原理:Global.asax 可以是asp.NET中應用程式或會話事件處理常式,我們用到了Application_Start(應用程式開始事件)和Application_End(應用程式結束事件)。
當應用程式開始時,啟動一個定時器,用來定時執行任務YourTask()方法,這個方法裡面可以寫上需要調用的邏輯代碼,可以是單線程和多線程。
當應用程式結束時,如IIS的應用程式集區回收,讓asp.Net去訪問當前的這個web地址,本地測試的時候寫本地地址,如http://localhost:82/111.aspx,到正式生產環境,可以改成你的web地址,如手機主題http://www.qumiao.comhttp://www.devdao.com等。
這裡需要訪問一個aspx頁面,這樣就可以重新啟用應用程式。
Log類是一個記錄日誌的一個類,下面是測試時產生的日誌資訊:
================================================================
2008-10-30 17:46:10:AutoTask is Working!
2008-10-30 17:46:15:AutoTask is Working!
2008-10-30 17:46:20:AutoTask is Working!
2008-10-30 17:46:23:Application End!
2008-10-30 17:46:29:AutoTask is Working!
2008-10-30 17:46:34:AutoTask is Working!
從日誌中發現,當手動回收IIS的應用程式集區之後,計劃任務還在執行,說明我們的目的達到了。
如果將Application_End中的代碼注釋掉,會發現Application End之後,計劃任務停止工作了,如下:
================================================================
2008-10-30 18:01:34:AutoTask is Working!
2008-10-30 18:01:39:AutoTask is Working!
2008-10-30 18:01:44:AutoTask is Working!
2008-10-30 18:01:46:Application End!
局限性:可以解決應用程式集區自動或者手動回收,但是無法解決IIS重啟或者web伺服器重啟的問題,當然這種情況出現的時候不多,而且如果有人訪問你的網站的時候,又會自動啟用計劃任務了。
Asp.net Global 定時執行