首先,不推荐在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