首先,不推薦在ASP.NET後臺中,啓動Long-Running的任務。由於不管是用的Task仍是ThreadPool.QueueUserWorkItem,ASP.NET不會知道它們在後臺運行,這會產生一些問題,好比:html
當修改web.config的時候,會觸發Appdomain被回收(儘管此時IIS web服務器進程w3wp.exe仍然活着),IIS自己也會每29小時回收應用程序池,這都會致使後臺線程被終止,從而引起異常。web
當ASP.NET要回收AppDomain,它會讓已經存在的請求處理完再回收,ASP.NET和IIS服務器也知道這些請求正在運行,因此等它們完成。問題是ASP.NET不知道任何後臺線程好比一個計時器或者其餘,它只知道和request相關的操做。c#
事實上,在後臺長時間的運行某些任務實在不是web server該作的事情,一般均可以用其餘的方式來避免這樣作,好比:windows
用console application和windows任務管理器,或者使用Windows服務等。安全
可是,若是肯定要這樣作,那麼在ASP.NET中也有些辦法保證後臺任務可以安全的退出。服務器
方法一,使用IRegisteredObject接口。app
經過IRegisteredObject接口,而且調用HostingEnvironment.RegisterObject方法在ASP.NET中註冊它。dom
當Appdomain要被回收的時候,會調用已註冊對象中的IRegisteredObject中的Stop方法。async
public interface IRegisteredObject { void Stop(bool immediate); }
已註冊對象沒有被取消註冊(即沒有調用HostingEnvironment.UnregisterObject方法來取消註冊),那麼Stop方法會被調用兩次,第一次調用的時候,immediate參數爲false,此時若是已註冊對象已經中止了,那麼應該調用 HostingEnvironment.UnregisterObject方法來取消註冊。若是還不取消註冊,那麼30秒後,該方法會被再次執行(這是最後的機會),不一樣的是此時傳入的immediate參數爲true,此時註冊對象必須先調用 UnregisterObject 方法而後返回;不然應用程序管理器將移除該對象的註冊。ide
使用IRegisteredObject接口並非用來處理後臺Long-Running任務的,可是這個功能可讓你安全的退出後臺任務。
舉個例子,以下:
public class JobHost : IRegisteredObject { private readonly object _lock = new object(); private bool _shuttingDown; public JobHost() { HostingEnvironment.RegisterObject(this); } public void Stop(bool immediate) { lock (_lock) { _shuttingDown = true; } HostingEnvironment.UnregisterObject(this); } public void DoWork(Action work) { lock (_lock) { if (_shuttingDown) { return; } work(); } } }
如上面的代碼,ASP.NET要回收Appdomain時,Stop 方法會被調用,這個方法會得到一個鎖,在DoWork方法也得到一樣的所,這樣的話,DoWork在運行的時候,Stop方法不得不等待。
方法二,使用HostingEnvironment.QueueBackgroundWorkItem
HostingEnvironment.QueueBackgroundWorkItem 方法在.NET4.5.2中引入,QueueBackgroundWorkItem (QBWI) 經過ASP.NET運行時,註冊後臺任務。這樣的話,因爲ASP.NET知道有後臺任務,他就不會當即回收Appdomain,固然,這不意味着後臺任務能夠作任何事情。當ASP.NET須要作回收的時候,它能夠經過一個CancellationToken通知後臺任務,而且等待30s讓工做完成。若是30秒內沒問出,那麼這個工做也會消失了。關於QueueBackgroundWorkItem的更多細節,能夠經過
方法二,使用HangFire
HangFire是一個開源的類庫,提供簡單的方法在ASP.NET中執行後臺Long-Running任務。這個類庫須要一些額外的存儲上的支持,SQLServer,Redis或者MSMQ。HangFire的資料在http://hangfire.io/
參考資料
http://blog.stephencleary.com/2014/06/fire-and-forget-on-asp-net.html