在做項目時,遇到同步ERP數據的問題,客戶要求是:程序中,設置一個開始時間,再設置一個時間間隔,讓程序每隔一段時間導出銷售記錄,這個開始時間和時間間隔可以手動修改設定。
這問題糾纏了我好幾天,總算解決了,寫文檔記錄:
首先,要讓程序定時執行任務,可以使用ASP.NET中的Timer計時,不過這個定時不是很准,如果用它,還會遇到其他的問題,后面會提到。第二種方法是,使用一個叫做:Quartz.NET開源項目,專門用來調度定時作業。
這次項目中,我用到的就是Quartz.NET組件,用他來定時調度作業,是很方便,不過問題也來了:當程序運行一段時間后,發現自動任務停止了。在網上查了查資料,說法不一。
后來多方查資料以及自己試驗證明:原來是網站應用程序在沒有請求時,過一定的時間就會停止應用程序,具體點來說,就是網站中的最后一個session結束時,網站應用程序就會結束。當然就會觸發Application_End事件。隨之定時任務也會停掉。
現在的問題就是:如何讓網站都有請求?如何讓Application_End事件不會發生?
這個問題在網上也有很多種說法,比如有人建議:在Application_End中用程序模擬請求網站,重新開始Application_Start事件,也給出了程序代碼:http://asdfblog.com/technology/aspnet-scheduled-tasks-with-quartznet.html這里有詳細說明。不過我照博主的做法,並沒有實現我想要的功能。不過他是用來處理IIS應用程序池回收的問題的。
孟子E章說:新建一個獨立的線程來調度執行的任務,個人認為比較麻煩,沒采用這種方式。
最后,發現了一個簡單的處理方式,利用ASP.NET的緩存超時技術。下面具體來闡明,基本思路:
在應用程序啟動時,用程序緩存一個網站中的頁面。在緩存網頁時,設置好緩存過期時間,以及緩存過期時觸發的回調事件,緩存過期時觸發的回調事件這是關鍵。在緩存過期時用程序模擬請求網站頁面,再次緩存,循環之…
代碼說明:(全在Global.asax里)
- private const string DummyPageUrl = "http:/index.aspx";
- private const string DummyCacheItemKey = "GagaGuguGigi";
- Quartz.IScheduler sched = SingletonScheduler.GetIntance();
- void Application_Start(object sender, EventArgs e)
- {
- //緩存頁面
- RegisterCacheEntry();
- }
- // 注冊一緩存條目在5分鍾內到期,到期后觸發的調事件
- private void RegisterCacheEntry()
- {
- if (null != HttpContext.Current.Cache[DummyCacheItemKey]) return;
- HttpContext.Current.Cache.Add(DummyCacheItemKey, "Test", null, DateTime.MaxValue,
- TimeSpan.FromMinutes(5), CacheItemPriority.NotRemovable,
- new CacheItemRemovedCallback(CacheItemRemovedCallback));
- }
- // 緩存項過期時程序模擬點擊頁面,阻止應用程序結束
- public void CacheItemRemovedCallback(string key, object value, CacheItemRemovedReason reason)
- {
- HitPage();
- }
- // 模擬點擊網站網頁
- private void HitPage()
- {
- System.Net.WebClient client = new System.Net.WebClient();
- client.DownloadData(DummyPageUrl);
- }
- protected void Application_BeginRequest(Object sender, EventArgs e)
- {
- if (HttpContext.Current.Request.Url.ToString() == DummyPageUrl)
- {
- RegisterCacheEntry();
- }
- }
這樣,網站應用程序就可以像運行windows服務一樣,在后台默默的執行了,沒看明白,可以參見這里:http://www.codeproject.com/KB/aspnet/ASPNETService.aspx
附:Quartz.Net詳細教程參見:
①官方教程:http://quartznet.sourceforge.net/tutorial/index.html;
②中文翻譯:http://www.cnblogs.com/shanyou/category/102991.html
====================================2013-8-2 后記================================================
在WebForm中使用Quartz.Net組件,個人測試結果,感覺也不夠穩定,最終是由 Winform客戶端程序+Quartz.NET組件實現,程序一直放在服務器上跑着。
為了防止服務器端程序停掉,可以寫成windows服務,這樣服務器一啟動,就會執行任務,只要服務器沒停,程序也會一直運行。
當然,這只能適用於獨立主機,虛擬空間就不行了。
附:
1.如何編寫windows服務:
http://msdn.microsoft.com/zh-cn/library/vstudio/9k985bc9.aspx
http://www.cnblogs.com/tuyile006/archive/2006/11/27/573654.html
2.windows服務輔助類:http://blog.csdn.net/a497785609/article/details/9103129
-----------------------------------------
設計IIS的解決方法
1.長期無用戶訪問網頁,asp.net 會自動進入Application_End事件(時間長短可以配置IIS)
2.修改web.config文件
3.刪除該站點下的文件夾之后,會自動進入Application_End
4.修改了bin目錄下的文件
5.重啟IIS
以上幾條都會觸發Application_End事件,如果你在asp.net的Application_State事件里做了一下應用(比如說定時器的計划任務)Application_End事件可能會使定時器停止。想要避免這種情況的發送就要注意要上面的幾個條件和修改IIS設置了。
IIS7 上可以通過設置應用程序池參數使其不會被簡單的自動回收來避免觸發Application_End事件。
在IIS中找到這個站點所用的程序池,點擊“高級設置...” 在打開的列表中更改以下設置:
回收——固定時間間隔(分鍾) 改為 0
——虛擬/專用內存限制(KB) 改為 0
進程模型——閑置超時(分鍾) 改為 0