前言
  在 ASP.NET 网站开发中,可能存在这样一个需求,我们希望网站后台能够每隔一段时间自动地执行某些任务,用定时器之类技术实现这个功能并不困难,但是在网站部署到IIS上的情况下,由于IIS应用程序池自动回收的原因,导致任务在IIS回收后中断,无法持续后台运行。
现在,我们就解决这个问题。
环境简介
这里是我当前的开发和部署所使用的环境。
系统环境
Windows 10 1903
开发环境
工具:Visual Studio 2019
SDK:.Netframework 4.6.2
部署环境
IIS Express
实现
先看看如何利用定时器实现后台任务
JobManager.cs
1 | using System; |
使用
JobManager.Start();
有关Timer的用法 可参考MSDN
前言提到过,单单这样实现的任务并不能保证后台执行,IIS 应用程序池自动回收的时候会毫不留情的将其摧毁。
下面有两种异曲同工的解决方式。
1.Application_End 中唤醒 IIS
  IIS的应用程序池进行回收的时候会调用Application_End 方法,有了这个条件,我们便可以在Application_End方法中做些文章了。
怎么做呢,我们只简单的访问一下自己的网就好了。
IIS 想休息,因为觉得没人拜访了,那我们就登门拜访。
关键代码如下所示
Global.asax.cs
1 | protected async void Application_End(object sender,EventArgs e) |
可能还需要写个日志来记录情况或者用HttpWebRequest来发起请求,都取决与聪明的你。
来看下一种方式。
2.IRegisteredObject 唤醒IIS
IRegisteredObject 接口
1 | public interface IRegisteredObject |
它是在System.Web.Hosting 下的一个接口,它是做什么用的呢?
搬运一下MSDN的描述 :
可以通过调用创建已注册对象的实例ApplicationManager.CreateObject的应用程序管理器中的方法。 应用程序管理器将新创建的对象返回给调用方,然后在对象调用特定于类型的方法。 在启动期间,已注册的对象应调用HostingEnvironment.RegisterObject方法以完成注册的对象。
当应用程序管理器需要停止已注册的对象时,它将调用Stop方法
简而言之,就是应用程序池将要回收的时候,会调用Stop方法,那么我们可以在Stop方法中实现与上面同样的逻辑。
IRegisteredObject 使用
首先要有一个类继承自 IRegisteredObject
1 | public class JobHost:IRegisteredObject |
在使用 JobHost 之前需要调用
HostingEnvironment.RegisterObject(this); 进行注册
在 Stop 方法被调用时调用
HostingEnvironment.UnregisterObject(this); 进行反注册
完整代码
通过第二种方式实现后台任务的完整代码
JobHost.cs
1 | class JobHost : IRegisteredObject |
JobManager.cs
1 | public class JobManager |
我这里说的可能不太详尽,如果想要参考更多细节,这里贴出参考的blog
The Dangers of Implementing Recurring Background Tasks In ASP.NET
最后
这个方法很简单,IIS总觉得当没人访问站点的时候,它就应该减少该站点的资源占用。
抱歉
“我不要你觉得,我要我觉得 。”
没错,不要偷懒。
当然,这是一个投机取巧的方式,用它来完成一些不那么重要和准确的任务是可以的,如果这些任务特别重要,应该考虑使用更稳定和适合的方式,比如,Windows 服务
参考
The Dangers of Implementing Recurring Background Tasks In ASP.NET