https://weblog.west-wind.com/posts/2013/Oct/02/Use-IIS-Application-Initialization-for-keeping-ASPNET-Apps-alive

 2013年10月2日•来自毛伊岛,HI•    37条评论
 

最近几个月我一直在使用Windows服务工作,而且事实证明,Windows服务是调试,部署,更新和维护的重要因素。获取服务设置,调试和更新的过程是一项重要的工作,必须进行广泛的文档记录和/或自动化。在构建服务的大多数项目中,人们最终争先恐后地争取用于管理的正确“流程”。另一方面,Web应用程序的部署和维护是常见的,并且现在已经很好理解,因为我们一直在处理Web应用程序。Web Tools中内置了大量基础架构和工具,如Visual Studio,以促进流程。相比之下,Windows服务或任何自托管的东西似乎令人费解。

事实上,在最近的一篇博文中,我提到在最近的一个项目中,我一直在Windows服务中使用自托管SignalR,因为该应用程序实际上是一个“服务”,也需要发送大量的消息通过SignalR。但实际情况是,它也可能是一个IIS应用程序,其中包含在后台运行的服务组件。无论你是哪种方式,它都是带有内置Web服务器的Windows服务,或运行服务应用程序的IIS应用程序,它们都不遵循标准的服务或Web应用程序模板。

我个人更喜欢Web应用程序。在IIS内部运行我获得了IIS平台的所有好处,包括服务生命周期管理(崩溃和重启),受控关闭,整个安全基础设施,包括简单的证书支持,代码的热插拔以及从中直接发布到IIS的能力在Visual Studio中轻松完成。

由于这些好处,我们开始从自托管服务转移到ASP.NET Web应用程序。

ASP.NET即服务的缺失链接:自动加载

过去我曾想在ASP.NET中运行“类似服务”的应用程序,因为当你考虑它时,远程控制Web应用程序要容易得多。服务被锁定在启动/停止操作中,但如果您在Web应用程序内部托管,则可以编写自己的票证并从任何位置控制它。事实上,差不多10年前,我构建了一个在ASP.NET内部运行的后台调度应用程序,它运行良好,并且它仍在运行,正在完成它的工作。

现在,在IIS内部运行应用程序作为服务的棘手部分是如何启动IIS和ASP.NET,以便即使在重置应用程序池后您的“服务”仍然存在。7年前,我通过使用网络监视器(我自己的West Wind Web Monitor应用程序)伪造它。我正在运行以监视我的各种网站的正常运行时间,并让监视器每隔20秒ping我的“服务”以有效地保持ASP。 NET存活或在重新加载后重新启动它。我使用了一个简单的调度程序类,它还包含一些“自我重新加载”的逻辑。Hacky肯定,但它可靠地工作。

幸运的是,一旦使用应用程序初始化模块启动应用程序池,就可以更轻松,更集成地让IIS启动ASP.NET。应用程序初始化模块基本上允许您打开应用程序池和站点/ IIS应用程序上的预加载,这实际上是在启动应用程序池后通过IIS管道发出请求。这意味着您的ASP.NET应用程序会立即生效,Application_Start会被激活,以确保您的应用始终保持运行状态。所有其他功能,如应用程序池回收和空闲时间后自动关闭仍然有效,但IIS将始终立即重新启动应用程序。

应用程序初始化入门

从IIS 8开始,Application Initialization是IIS功能集的一部分。对于IIS 7和7.5,可通过Web Platform Installer 单独下载。使用IIS 8应用程序初始化是Windows或Windows Server Role Manager中的可选安装组件:

这是一个可选组件,因此请确保明确选择它。

应用程序初始化的IIS配置

需要在应用程序池和IIS应用程序级别上应用初始化。从IIS 8开始,可以通过IIS管理控制台进行这些设置。

从应用程序池开始:

在这里,你需要设置两种自动开始其始终设置,并应设置为AlwaysRunning的STARTMODE。两者都必须设置 - 默认情况下,Start Automatically标志设置为true,并控制应用程序池本身的启动,而启动应用程序则需要Always Running标志。如果没有设置后一个标志,则站点设置无效。

现在,在站点/应用程序级别,您可以指定站点是否应预加载:

Preload Enabled标志设置为true。

此时,ASP.NET应用程序应自动加载。如果你想要的只是让你的网站自动启动,这就是预加载网站所需的全部内容。

如果您想要更多地控制加载过程,可以在web.config文件中添加一些设置,以便在应用程序启动时显示静态页面。如果启动速度很慢,这可能很有用,因此,当用户摆弄拇指时,您可以显示静态HTML页面,而不是显示空白屏幕:

  < system.webServer >
< applicationInitialization remapManagedRequestsTo = “ Startup.htm ”
skipManagedModules = “ true ” >
< add initializationPage = “ ping.ashx ” />
</ applicationInitialization >
</ system.webServer >

这允许您指定要在空运行中执行的页面。IIS基本上伪造请求并将其直接推送到IIS管道而不会访问网络。您指定一个页面,IIS将伪造对该页面的请求,在这种情况下ping.ashx只返回一个简单的OK字符串 - 即。快速的管道请求。应用程序池重新启动后立即运行此请求,当此请求正在运行且您的应用程序正在预热时,IIS可以显示备用静态页面 - 上面的Startup.htm。因此,当您点击网站上的链接时,您可以选择显示某种静态状态页面,而不是向用户显示空的加载页面,“我们会马上回来”。我不确定这是不是一个好主意,因为在某些情况下这可能会非常具有破坏性。我个人认为我更喜欢让人们等待,但至少得到他们应该回来的回应而不是随机页面。但是如果你需要它就在那里。

请注意,web.config内容是可选的。如果您不提供IIS,则会访问默认站点链接(/),即使在该请求结束时没有匹配的请求,它仍将通过IIS管道触发请求。理想情况下,您希望确保使用默认页面命中ASP.NET端点,或者通过指定initializationPage以确保ASP.NET实际受到攻击,因为IIS可能仅针对静态页面触发非托管请求(取决于您的方式)管道已配置)。

AppDomain重启怎么样?

除了IIS级别的完整工作进程回收之外,ASP.NET还必须处理AppDomain关闭,这可能由于各种原因而发生:

  • 文件在BIN文件夹中更新
  • Web部署到您的站点
  • web.config已更改
  • 硬应用程序崩溃

这些操作不会导致工作进程重新启动,但它们确实会导致ASP.NET卸载当前的AppDomain并启动新的AppDomain。由于上述功能仅适用于应用程序池重新启动,因此AppDomain重新启动也可能导致“ASP.NET服务”在后台停止处理。

为了使应用程序在AppDomain上循环运行,您可以在Application_End事件中使用简单的ping:

protected void Application_End()
{
var client = new WebClient ();
var url = App .AdminConfiguration.MonitorHostUrl + “ping.aspx” ;
client.DownloadString(URL);
Trace .WriteLine(“应用程序关闭Ping:” + url);
}

它会在管道关闭的最后将任何ASP.NET URL激活到当前站点,从而确保站点立即重新启动。

ApplicationHost.config中的手动配置

上面的UI对应于以下ApplicationHost.config设置。如果您使用的是IIS 7,则这些标志没有UI,因此您必须手动编辑它们。

将Application Initialization组件安装到IIS时,它应该将模块自动配置为ApplicationHost.config。对我来说不幸的是,墨菲先生对我来说是最好的形式,模块注册没有发生,我不得不手动添加它。

< globalModules >
< add name = “ ApplicationInitializationModule ”
image = “ %windir%\ System32 \ inetsrv \ warmup.dll ” />
</ globalModules >

很可能你不需要添加它,但如果事情不起作用,那么检查模块是否实际注册是值得的。

接下来,您需要配置ApplicationPool和Web站点。以下是ApplicationHost.config中的两个相关条目。

< system.applicationHost >
< applicationPools >
< 添加名称= “ 西风西风Web连接
AUTOSTART = “ 真”
STARTMODE = “ AlwaysRunning ”
managedRuntimeVersion = “ V4.0 ”
managedPipelineMode = “ 集成” >
< processModel identityType = “ LocalSystem ”
setProfileEnvironment = “ true ” />
</ add >
</ applicationPools > < sites >
< site name = “ 默认网站” id = “ 1 ” >
< application path = “/ MPa.Workflow.WebQueueMessageManager ”
applicationPool = “ West Wind West Wind Web Connection
preloadEnabled = “ true ” >
< virtualDirectory path = “ / ”
physicalPath = “ C:\ Clients \ ... ” />
</ application >
</ site >
</ sites >
</ system.applicationHost >

在应用程序池上,确保将autoStart和startMode标志分别设置为true和AlwaysRunning。在站点上,确保将preloadEnabled标志设置为true。

这就是你应该需要的。您仍然可以设置上述web.config设置。

ASP.NET即服务?

在我目前正在处理的特定应用程序中,我们有一个队列管理器,它作为独立服务运行,轮询数据库队列并选择作业并在多个线程上处理它们。该服务可以启动任意数量的线程,并在IIS运行时自己将这些线程保持活动状态。这些线程是新创建的线程,因此它们完全位于IIS线程池之外。为了使这项服务能够工作,它所需要的只是一个长时间运行的引用,它可以在应用程序的整个生命周期内保持活动状态。

在这个特定的应用程序中,有两个组件在后台运行在自己的线程上:一个调度程序,它运行各种计划任务并处理诸如拾取电子邮件以发送到IIS范围之外的事件和QueueManager。

以下是global.asax中的内容:

公共类Global :System.Web。HttpApplication { private static ApplicationScheduler scheduler; 私有静态ServiceLauncher 发射器; protected void Application_Start(object sender,EventArgs e) { // ping服务并确保它保持活动 scheduler = new ApplicationScheduler () { CheckFrequency = 600000 }; scheduler.Start(); launcher = new ServiceLauncher (); launcher.Start(); //注册所以关闭是受控的 HostingEnvironment .RegisterObject(启动器); }

}

通过将这些对象保持为在启动时仅设置一次的静态实例,它们可以在应用程序的生命周期中存活。除了我可以删除Windows服务接口(OnStart,OnStop,OnResume等)所需的各种覆盖之外,这些类中的代码与Windows服务代码基本相同。否则行为和操作非常相似。

在这个应用程序中,ASP.NET有两个目的:它充当SignalR的主机,并提供允许远程管理“服务”的管理界面。我可以通过非常轻松地关闭ApplicationScheduler来远程启动和停止服务。我也可以通过SignalR服务直接通过几个Web请求或(如我们现在所做)直接从队列中提取统计信息。

使用ASP.NET注册后台对象

另请注意HostingEnvironment.RegisterObject()的使用。此函数向ASP.NET注册一个对象,让它知道它是一个后台任务,如果AppDomain关闭,应该通知它。RegisterObject()需要一个带有Stop()方法的接口,该方法被触发并允许代码响应关闭请求。以下是启动器上IRegisteredObject :: Stop()方法的样子:

public void Stop(bool immediate = false )
{
LogManager .Current.LogInfo(“QueueManager Controller Stopped。” ); Controller.StopProcessing();
Controller.Dispose();
Thread .Sleep(1500); //给一些背景线程 HostingEnvironment .UnregisterObject(this );
}

实现IRegisterObject应该有助于AppDomain关闭的可靠性。感谢Justin Van Patten在推特上向我指出这一点。

RegisterObject()不是必需的,但我强烈建议在AppDomain关闭时,在后台处理所有干净关闭的任何对象控件上实现它。

测试出来

我仍然处于这个特定服务的测试阶段,看看是否有任何副作用。但到目前为止看起来并不像。通过大约50行代码,我能够将Windows服务启动替换为Web启动 - 其他一切都按原样工作。值得一提的是SignalR 2.0的oWin托管,因为新的基于oWin的托管不需要代码更改,只需要几个配置文件设置和汇编指令,指向SignalR启动类。甜!

与自托管相比,似乎SignalR在IIS内运行速度明显更快。由于预加载,启动感觉更快。

启动和停止“服务”

由于应用程序作为Web服务器运行,因此可以轻松地使用Web界面来启动和停止在服务内部运行的服务。对于我们的队列管理器,SignalR服务和前端监控应用程序有一个用于切换队列的播放和停止按钮。

如果您想要更多的管理控制并使其更像Windows服务,您还可以从命令行显式停止应用程序池,这相当于停止和重新启动服务。

要从命令行启动和停止,您可以使用IIS appCmd工具。停止:

>%windir%\ system32 \ inetsrv \ appcmd stop apppool /apppool.name:"Weblog“

并开始

>%windir%\ system32 \ inetsrv \ appcmd start apppool /apppool.name:"Weblog“

请注意,当您明确强制AppPool停止在UI(在ApplicationPools页面上使用Start / Stop)或通过命令行工具运行时,应用程序池将不会立即自动重新启动。您必须手动启动它。

有什么不喜欢的?

在IIS中运行后台服务肯定有很多好处,但是...... ASP.NET应用程序在内存占用方面确实有更多的开销,启动时间稍微慢一些,但通常对于服务器应用程序来说这不是什么大问题。如果应用程序稳定,则服务应该启动并无限期地保持运行。很多时候,这种服务接口可以简单地附加到现有的Web应用程序,或者如果需要将可伸缩性卸载到它自己的Web服务器上。

更容易使用

但这里的最终好处是使用Web应用程序而不是服务更容易。在开发过程中,我可以简单地通过点击网站上的页面来关闭自动启动功能并通过IIS按需启动服务。如果我想关闭IISRESET -stop将足够轻松地关闭服务。然后我可以在任何我想要的地方附加一个调试器,这就像任何其他ASP.NET应用程序一样。是的,你最终会在后台线程上进行调试,但是Visual Studio处理得很好,如果你留在一个线程上,这与调试任何其他代码没什么不同。

摘要

使用ASP.NET运行后台服务操作可能不是一个超常见的场景,但它可能应该是构建服务时仔细考虑的事情。许多应用程序具有类似于服务的功能以及Application Initialization模块的自动启动功能,因此很容易将此功能构建到ASP.NET中。特别是当与SignalR的通知功能结合使用时,创建丰富的服务变得非常非常容易,这些服务也可以轻松地将其状态传达给外界。

无论是现有的应用程序需要一些后台处理来安排相关任务,还是只是创建一个单独的站点来托管您的服务,这很容易做到,您可以利用您已经用于其他Web项目的相同工具链。如果你有很多服务项目,值得考虑......给它一些思考......

 
 

使用IIS应用程序初始化来保持ASP.NET应用程序的活动的更多相关文章

  1. ASP.NET学习笔记——ASP.NET应用程序

    0 剖析ASP.NET应用程序 用户运行ASP.NET应用程序,不是直接运行,而是使用浏览器(比如IE)通过HTTP请求一个特定的URL(如http://www.mysite.com/mypage.a ...

  2. 在ASP.NET应用程序中使用身份模拟(Impersonation)

    摘要   缺省情况下,ASP.NET应用程序以本机的ASPNET帐号运行,该帐号属于普通用户组,权限受到一定的限制,以保障ASP.NET应用程序运行的安全.但是有时需要某个ASP.NET应用程序或者程 ...

  3. 【Asp.net入门05】第一个ASP.NET 应用程序-测试Asp.net程序

    测试示例应用程序 本部分内容: ASP.NET应用程序测试方法 web窗体访问过程 Visual Studio工具栏上有一个下拉列表,其中列出了工作站上已安装的浏览器的名称(单击浏览器名称右侧的向下箭 ...

  4. IIS 7.0 的 ASP.NET 应用程序生命周期概述(转载)

    IIS 7.0 的 ASP.NET 应用程序生命周期概述更新:2007 年 11 月本主题介绍在 IIS 7.0 集成模式下运行以及与 IIS 7.0 或更高版本一起运行的 ASP.NET 应用程序的 ...

  5. C# -- HttpWebRequest 和 HttpWebResponse 的使用 C#编写扫雷游戏 使用IIS调试ASP.NET网站程序 WCF入门教程 ASP.Net Core开发(踩坑)指南 ASP.Net Core Razor+AdminLTE 小试牛刀 webservice创建、部署和调用 .net接收post请求并把数据转为字典格式

    C# -- HttpWebRequest 和 HttpWebResponse 的使用 C# -- HttpWebRequest 和 HttpWebResponse 的使用 结合使用HttpWebReq ...

  6. IIS 5.0 和 6.0 的 ASP.NET 应用程序生命周期概述

    本主题概述 ASP.NET 应用程序的生命周期,列出了重要的生命周期事件,并描述了您编写的代码将如何适应于应用程序生命周期.本主题中的信息适用于 IIS 5.0 和 IIS 6.0.有关 IIS 7. ...

  7. IIS下Asp.Net应用程序多进程设置及Session共享

    背景: 目前项目中在单个进程的应用程序经常会遇到w3c.exe崩溃的情况,于是就设想是否可以通过IIS多进程的方案来避免出现该问题. 于是搜了下“怎么实现多进程的方案”,找到了这篇文章:http:// ...

  8. 在 IIS 中配置 ASP.NET 应用程序

     注意事项: 1.注册.NET 如果先安装.net平台,后安装IIS,那么在IIS中可能就没有出现ASP.NET版本的下拉菜单,就要手动注册: 一般.Net版本都存放在:C:\WINDOWS\Micr ...

  9. IIS 7.0 的 ASP.NET 应用程序生命周期概述

    文章:IIS 7.0 的 ASP.NET 应用程序生命周期概述 地址:https://msdn.microsoft.com/zh-cn/library/bb470252(v=vs.100).aspx ...

随机推荐

  1. 【CH2401】送礼物

    题目大意:NPC 子集和问题. 题解:先搜索一半的物品重量和,记录在一个数组中,并将该数组排序并去重.再搜索另一半物品,到达目标状态后,在前一半物品记录的重量中查找小于当前剩余重量的最大值,更新答案即 ...

  2. 公共DNS推荐及dns测速

    DNS在平时上网中扮演重要角色,如果不注意DNS的话,可能会导致网速慢.弹窗广告.网址打不开.打开不是自己想要的网站.劫持等一系列问题.针对DNS的问题,今天我们就来总结一下,看看哪个DNS服务器最好 ...

  3. Java单例模式之最优解分析【为何说是最优解】

    代码如下 /** * * @ClassName: SingletionStaticInner * @Description: TODO[单例模式之最优解] * @author shundong.wu ...

  4. linux下mysql的数据库简单备份脚本

    应用于整个库的备份. #!/bin/bash PATH=$PATH:/usr/local/mysql/bin:/usr/local/mysql/sbin # 数据库名称 databases=(myna ...

  5. Java发布webservice应用并发送SOAP请求调用

    webservice框架有很多,比如axis.axis2.cxf.xFire等等,做服务端和做客户端都可行,个人感觉使用这些框架的好处是减少了对于接口信息的解析,最主要的是减少了对于传递于网络中XML ...

  6. mysql的order by注入

    最近在做一些漏洞盒子后台项目的总结,在盒子众多众测项目中,注入类的漏洞占比一直较大.其中Order By注入型的漏洞也占挺大一部分比例,这类漏洞也是白帽子乐意提交的类型(奖金高.被过滤概览小).今天给 ...

  7. Java(19)JDBC

    一.使用jdbc的步骤 a.引入数据库厂商提供的驱动程序(引入jar包) b.记载驱动程序 Clss.forName("驱动程序类") c.获得连接 Connection con ...

  8. Arduino—运算符

    赋值运算符: =    +=   -+     *=      /= %=       取余等于 &=    与等于 &=(与等于)对某个变量的值按位进行与运算,例如:G&=x ...

  9. 从XML文件和properties文件提取数据

    XML文档格式内容如下 <?xml version="1.0" encoding="UTF-8"?> <root>     <fi ...

  10. I\O操作

    作用:读写设备上数据.硬盘文件.内存.键盘.网络等. 分类: 数据走向:输入流.输出流 数据类型:字符流(文本数据Reader或者Writer结尾) 字节流(所有类型Stream结尾) 1个字节 = ...