IIS 8.0 应用程序初始化

作者:Shaun Eagan

兼容性

版本 说明
IIS 8.0 应用程序初始化内置于 IIS 8.0。
IIS 7.5 应用程序初始化作为 IIS 7.5 的带外模块发布。
IIS 7.0 IIS 7.0 不支持应用程序初始化。

问题

网站管理员面临的常见问题是需要为 Web 应用程序执行初始化任务和“预热”任务。 较大且更复杂的 Web 应用程序可能需要执行较长的启动处理、内存中的主要缓存、生成内容等...这些都在提供第一个 HTTP 请求之前发生。

解决方案

IIS 8.0 应用程序初始化功能使网站管理员能够将 IIS 8.0 配置为主动执行一个或多个 Web 应用程序的初始化任务。 在初始化应用程序时,IIS 8.0 还可以配置为将静态内容作为占位符或“启动页面”返回,直到应用程序完成其初始化任务。

应用程序初始化功能是通过全局规则和特定于应用程序的规则的组合配置的,这些规则告知 IIS 8.0 如何以及何时初始化 Web 应用程序。 应用程序初始化功能还支持与 IIS URL 重写模块的集成,以支持在应用程序仍在初始化时对占位符内容进行更复杂的处理。

注意

应用程序初始化与应用程序请求路由 (ARR) 之间存在已知的不兼容问题。 不建议在安装了 ARR 的计算机上使用应用程序初始化。

分步说明

先决条件

应用程序初始化功能需要安装 IIS 8.0。 此外,需要安装 IIS“应用程序开发”子功能中的应用程序初始化功能。

Windows Server 2012 Server Manager UI 中的以下屏幕截图显示了应用程序初始化功能。

Screenshot showing the Application Initialization feature installed on Windows Server 2012.

注意

本演练还使用 ASP.NET 4.5 应用程序来演示应用程序初始化功能。 本文档末尾的附录包括示例应用程序和有关在计算机上设置应用程序的说明。

已知 bug 的解决方法

  • 此功能目前没有已知的 bug。

全局应用程序初始化

可以在两个位置配置应用程序初始化功能:计算机范围的 applicationHost.config 文件和应用程序级 web.config 文件。 applicationHost.config 文件中的配置包含“全局”应用程序初始化设置,而应用程序级 web.config 文件包含“local”应用程序初始化设置。

在本演练中,将示例应用程序配置为在与应用程序关联的应用程序池启动时始终初始化。 由于应用程序池行为只能在 applicationHost.config 中配置,因此每当应用程序池启动时运行应用程序初始化被视为“全局”应用程序初始化设置的一部分。

applicationHost.config 中的修改

打开位于记事本中 %WINDIR%\system32\inetsrv\config 的 applicationHost.config 文件。 (请记住使用“以管理员身份运行”选项运行文本编辑器!)

找到 <applicationPools> 配置部分,然后查找名为“.NET v4.5”的应用程序池条目。

修改应用程序池条目,使应用程序池始终运行。 对于希望进行全局应用程序初始化的应用程序,通常希望启动并运行关联的应用程序池。 配置片段中的加粗属性显示要添加到配置条目的内容。

<add name=".NET v4.5" startMode="AlwaysRunning" managedRuntimeVersion="v4.0" />

将 applicationHost.config 中的更多内容向下滚动到 <sites> 配置元素。 在该部分中,示例应用程序会有一个 <application> 条目(有关在计算机上创建示例应用程序的说明,请参阅附录)。 应用程序称为“appinit”,其路径属性值为“/appinit”。 通过添加加粗的 preloadEnabled 属性来修改 <application> 条目,如配置代码片段中所示,然后保存更改。

<application path="/appinit" preloadEnabled="true" applicationPool=".NET v4.5">

preloadEnabled 设置为“true”会告知 IIS 8.0 当关联的应用程序池启动时,它会向应用程序发送“fake”请求。 这就是为什么在上一步中,我们将应用程序池的 startMode 设置为“AlwaysRunning”。

随着应用程序池的组合始终运行,并且应用程序本身被标记为始终接收虚假请求,每当计算机重启和/或万维网服务被回收时,IIS 8.0 可确保应用程序池实例正在运行,并且应用程序“/appinit”始终发送虚假请求来触发应用程序启动。

应用程序的 web.config 中的修改

使用记事本的第二个实例打开位于以下位置的应用程序级别 web.config 文件。 (请记住使用“以管理员身份运行”选项运行文本编辑器!)

C:\inetpub\wwwroot\appinit

注意:如果默认网站安装在其他物理驱动器上,请更改驱动器号。

web.config 文件已预先填充了几个配置节,但已注释禁止。取消注释显示在配置节内的 <system.webServer> 配置代码段。 此代码片段位于 web.config 文件中的注释“练习 1 - 步骤 1”下方。 保存更改。

<applicationInitialization
    remapManagedRequestsTo="Startup.htm" 
    skipManagedModules="true" >
  <add initializationPage="/default.aspx" />
</applicationInitialization>

applicationInitialization 元素告诉 IIS,它应向应用程序的根 URL(在此示例中为“/default.aspx”)发出请求来初始化应用程序。 当 IIS 等待请求“/default.aspx”完成时,它将向任何活动浏览器客户端提供“Startup.htm”。 “Startup.htm”是应用程序的“启动页面”。

运行应用程序

提升的命令提示符窗口中,使用如下所示的命令回收万维网服务:

net stop w3svc & net start w3svc

请记得使用“以管理员身份运行”选项打开命令提示符窗口。

使用 Internet Explorer 导航到以下 URL:

http://localhost/appinit/default.aspx

浏览器在前几秒钟返回具有灰色背景的静态“Startup.htm”页面,因为这是在 web.config 中配置的“启动页面”。可以在 Web 浏览器中继续刷新页面,并观察大约 8 秒后(在示例应用程序的 global.asax 中使用线程睡眠模拟)后,会收到具有白色背景的default.aspx的“真实”内容。 这表示应用程序初始化已完成。

配置重叠的进程回收

IIS 8.0 通过在后台的重叠进程中执行应用程序初始化,将全局应用程序初始化与重叠的进程回收集成。 当 IIS 检测到正在回收活动工作进程时,IIS 不会将活动流量切换到新的已回收工作进程,直到新工作进程完成在新进程中运行所有应用程序初始化 URL。 这可确保在应用程序实时运行并运行后,浏览网站的客户不会看到应用程序初始化页面。

返回到具有 applicationHost.config 的记事本实例。修改“.NET v4.5”的应用程序池条目,使其类似于下图所示的配置代码段:

<add name=".NET v4.5"
                startMode="AlwaysRunning"
    managedRuntimeVersion="v4.0" >
  <recycling logEventOnRecycle="Schedule">
    <periodicRestart requests="30" />
  </recycling>
</add>

请记得保存更改!

<回收> 元素告知 IIS 每 30 个 HTTP 请求回收一次工作进程。

再次运行应用程序

提升的命令提示符窗口中,使用如下所示的命令回收万维网服务:

net stop w3svc & net start w3svc

使用 Internet Explorer 的新实例再次导航到:

http://localhost/appinit/default.aspx

请注意,显示灰色背景的“Startup.htm”启动页面。

接下来,拉取任务管理器并确保显示“进程”选项卡。 按名称对进程列表进行排序,直到看到一个 w3wp.exe 实例正在运行。 该实例是当前运行“appinit”ASP.NET 应用程序的工作进程。

Screenshot showing the Task Manager process list running one instance of the w 3 w p executable file.

刷新浏览器几次,直到返回真实 default.aspx 页中的内容。 当后台更改为白色时,便可知道应用程序正在运行“真实”的 default.aspx 页面。 接下来,排列屏幕上的窗口,以便你可以看到任务管理器和浏览器。

现在切换回浏览器并刷新页面至少 30 次,这会导致 IIS 回收应用程序池。 在任务管理器进程列表中显示如下所示的第二个 w3wp.exe 实例时,可以停止刷新页面:

Screenshot showing the second instance of the w 3 w p executable file in the Task Manager process list.

屏幕截图显示了由于前面设置的进程回收限制而启动 w3wp.exe 的第二个实例。

可以在接下来的 10 秒左右继续不时刷新浏览器窗口。 请注意,default.aspx 会继续运行。 当重叠的回收完成时,一个 w3wp.exe 实例会从“任务管理器进程”窗口中消失。

在重叠回收期间,你继续看到服务“真实”的 default.aspx 的内容,即使应用程序初始化已为应用程序配置,并且已在 w3wp.exe 的新实例的后台运行初始化 URL。

URL 重写和应用程序初始化

默认情况下,应用程序初始化仅允许指定在应用程序初始化时显示的单个“启动页面”URL。 但是,应用程序初始化功能支持一些服务器变量,这些变量可用于在应用程序初始化时控制请求处理。 这使你能够使用 URL 重写模块创建声明性规则,该模块包含到预生成的静态内容的更复杂的映射。

在本演练中,你将 remapManagedRequestsTo 属性替换为一组完成相同结束结果的 Url 重写规则。

注意:有关安装 URL 重写的说明,请参阅附录。

applicationHost.config 中的修改

使用已打开 applicationHost.config 的记事本实例,还原应用程序池和应用程序元素以关闭所有全局应用程序初始化处理。 此步骤中移除了全局设置,因为本演练的其余部分侧重于配置的应用程序初始化行为。

应用程序池和应用程序的 applicationHost.config 条目如下所示。

应用程序池配置条目:

<add name=".NET v4.5" managedRuntimeVersion="v4.0" />

应用程序配置条目:

<application path="/appinit" applicationPool=".NET v4.5">

请记得在完成时保存更改!

此外,若要确保更改在 IIS 中生效,请在提升的命令提示符窗口中使用如下所示的命令回收万维网服务:

net stop w3svc & net start w3svc

对应用程序级别 web.config 的修改

使用打开应用程序级 web.config 的记事本实例,从 <applicationInitialization> 元素中移除 remapManagedRequestsTo 属性。 现在,<applicationInitialization> 配置部分应类似于此配置片段。

<applicationInitialization skipManagedModules="true" >
  <add initializationPage="/default.aspx" />
</applicationInitialization>

由于 <applicationInitialization> 元素不再定义要重新映射请求的 URL,因此请添加一组 URL 重写规则。 接下来,添加一个重写规则,用于显式映射对“default.aspx”发出的请求,以及“/”以路由到“Startup.htm”。 需要两个规则,因为 URL 重写模块不知道默认文档的工作原理。 由于“/”等同于 ASP.NET 应用程序中的“default.aspx”,你需要两个 URL 重写规则 - 每个 URL 变体的一个规则。

下面以粗体显示新规则。 或者,可以在 web.config 文件中的“练习 2 - 步骤 2 映射请求到主页”注释下取消注释预填充的 URL 重写规则。

<rewrite> 
  <rules>
    <rule name="Home Page-Expanded" stopProcessing="true">
      <match url="default.aspx" />
      <conditions>
        <add input="{APP_WARMING_UP}" pattern="1" />
      </conditions>
      <action type="Rewrite" url="Startup.htm" />
    </rule>
    <rule name="Home Page-Short" stopProcessing="true">
      <match url="^$" />
      <conditions>
        <add input="{APP_WARMING_UP}" pattern="1" />
      </conditions>
      <action type="Rewrite" url="Startup.htm" />
    </rule>
  </rules>
</rewrite>

要记下这些规则的某些项:首先,stopProcessing 属性在<规则/ > 元素上设置为“true”。 对于稍后添加全面覆盖的 Url 重写规则,以及对于不希望全面覆盖规则运行的 default.aspx 或“/”请求,此操作是必要的。

其次,请注意,<条件 /> 元素中有 URL 重写条件。 此条件实际上表示“仅当应用程序处于初始化状态时应用规则”。 当应用程序初始化处于活动状态并且 IIS 仍在处理所有初始化 URL 时,服务器变量“APP_WARMING_UP”设置为“1”。

最后,请注意,已定义该操作以重写活动请求,改为运行“Startup.htm”。 此规则的作用是告诉 IIS 将请求传递给静态文件处理程序,然后呈现静态页面 Startup.htm。

接下来,添加一个全面覆盖的重写规则。 将 URL 重写模块与应用程序初始化结合使用时,如果不需要以前的规则匹配,则会触发一个全面覆盖规则。 将下面显示的加粗规则添加到重写部分作为全面覆盖规则。 或者,可以在 web.config 中的“练习 2 - 步骤 2 设置全面覆盖规则”注释下取消注释的 web.config 中预填充的全面覆盖规则。

<rewrite> 
  <rules>
    <rule name="Home Page-Expanded" stopProcessing="true">
      <match url="default.aspx" />
      <conditions>
        <add input="{APP_WARMING_UP}" pattern="1" />
      </conditions>
      <action type="Rewrite" url="Startup.htm" />
    </rule>
    <rule name="Home Page-Short" stopProcessing="true">
      <match url="^$" />
      <conditions>
        <add input="{APP_WARMING_UP}" pattern="1" />
      </conditions>
      <action type="Rewrite" url="Startup.htm" />
    </rule>
    <rule name="All Other Requests">
      <match url=".*" />
      <conditions>
        <add input="{APP_WARMING_UP}" pattern="1" />
      </conditions>
      <serverVariables>
        <set name="SKIP_MANAGED_MODULES" value="0" />
      </serverVariables>
      <action type="Rewrite" url="{URL}" />
    </rule>
  </rules>
</rewrite>

完成后保存更改!

新规则与到达它的任何 URL 匹配,并指示 IIS 继续处理对入站 URL 发出的请求。 该规则还会将名为“SKIP_MANAGED_MODULES”的服务器变量设置为“0”的值,这相当于“false”。 此设置告知 IIS,它应以与请求正常到达线路时相同的方式处理 URL 重写请求。

运行应用程序

在提升的命令提示符窗口中,使用如下所示的命令回收万维网服务:

net stop w3svc & net start w3svc

使用 Internet Explorer 的新实例再次导航到:

http://localhost/appinit/default.aspx

尽管 URL 重写规则现在用于定义初始页逻辑,但仍会看到第一个演练中的相同行为。 最初显示带有灰色背景的 Startup.htm 页。 如果定期刷新浏览器,大约八秒钟后,再次看到页面背景切换为白色,表明现在应用程序初始化已完成,表示正在提供“真实”的 default.aspx 页面。

复杂初始页规则

前面的演练使用应用程序初始化作为 URL“X”到 URL“Y”的直接映射。 在本演练中,你将实现更复杂的应用程序初始化方案。

在浏览器中导航到以下两个 URL:

  • http://localhost/appinit/ImageHandler.ashx?image=Lighthouse
  • http://localhost/appinit/ImageHandler.ashx?image=Tulips

这些 URL 是动态生成的静态内容的示例。 对于此示例应用程序,ImageHandler.ashx 中的代码将查看查询字符串键“image”。 如果该查询字符串的值是“Lighthouse”或“Tulips”,则 ASP.NET 处理程序将传输位于 App_Data 文件夹中的相应 JPG。

由于图像处理程序只是返回图像,因此即使在应用程序初始化期间,你仍能够继续返回适当的图像。 尽管为这些映像提供服务的机制使用托管代码,但你可能希望快速向客户提供预生成的映像,即使基础 ASP.NET 应用程序需要很长时间才能启动和初始化自身。

对应用程序级别 web.config 的修改

使用打开应用程序级 web.config 的记事本实例,在最终的全面覆盖规则之前添加另一个 URL 重写规则。 要添加的新代码片段如下所示。 或者,可以在 web.config 中的“练习 3 - 步骤 1 复杂初始页规则”注释下取消注释 web.config 中预填充的图像处理程序规则。

<rule name="Image Handler Remapping" stopProcessing="true">
  <match url="ImageHandler.ashx" />
  <conditions>
    <add input="{APP_WARMING_UP}" pattern="1" /> 
    <add input="{QUERY_STRING}" pattern="image=([A-Za-z]+)&amp;?" /> 
  </conditions>
  <action type="Rewrite" url="Images/{C:1}_static.jpg" appendQueryString="false" />
</rule>

完成后保存更改。

与 default.aspx 和“/”的重写规则一样,此规则的 stopProcessing 属性设置为“true”,以确保对 ImageHandler.ashx 的请求不会意外地回退到应用程序初始化期间的最终全面覆盖重写规则。

对于对“ImageHandler.ashx”的请求,重写规则使用正则表达式捕获组从查询字符串中提取请求的图像。 匹配模式定义模式=“image=([A-Za-z]+)&?” 指示 IIS 提取“image”查询字符串变量的值。 然后,该值在操作属性的 URL 属性中使用:url="Images/{C:1}_static.jpg"

操作元素上的 url 属性告知 Url 重写模块重写 ImageHandler.ashx 请求,以改为指向应用程序的 Images 子目录中的文件。 此外,正则表达式捕获的查询字符串值用于帮助形成最终将从 Images 子目录提供的文件的名称。 例如,对 ImageHandler.ashx?image=Tulips 的请求将重写为 Images/Tulips_static.jpg

如果使用 Windows 资源管理器浏览到 inetpub\wwwroot\appinit 目录并查看 Images 子目录,则会看到两个文件:一个文件表示 Tulips.jpg 的“静态”版本,另一个文件表示 Lighthouse.jpg 的“静态”版本。 这些静态图像充当可在应用程序初始化时提供的预生成内容。

运行应用程序

在提升的命令提示符窗口中,使用如下所示的命令回收万维网服务:

net stop w3svc & net start w3svc

使用 Internet Explorer 导航到以下任一项:

http://localhost/appinit/ImageHandler.ashx?image=Lighthouse

http://localhost/appinit/ImageHandler.ashx?image=Tulips

请注意两种情况下返回的图像如何包括水印,指示这些图像是映像的“静态”预生成版本。 水印是图像上半部分的文本,上面写着“此图像是静态版本的...”。

如果在大约 10 秒后刷新浏览器,则会看到返回的图像内容更改为 ImageHandler.ashx 处理程序提供的“真实”内容。 水印消失,这表示内容现在正由 ASP.NET 处理程序动态生成,因为应用程序已完成初始化。

[注意:如果 Internet Explorer 似乎未刷新,请单击地址栏中的“损坏的文档”图标或刷新图标以强制 Internet Explorer 重新加载页面。]

总结

IIS 8.0 应用程序初始化功能使开发人员和管理员能够在 IIS 初始化“冷”应用程序时将静态内容返回到浏览器。 立即向浏览器提供静态内容可为客户提供更好的用户体验。 应用程序初始化功能可用于提供相关的静态内容,而基础应用程序完成昂贵的初始化处理,而不是使用冷启动应用程序生成空白浏览器页或旋转等待图标。

每当 Web 服务器联机或回收时,都会自动执行初始化过程。 对于服务器管理员不想贪婪地初始化应用程序的情况,当第一个请求到达“冷”应用程序时,可以按需触发初始化过程。

对于全局和本地应用程序初始化,URL 重写模块可以集成以提供更丰富且更复杂的初始化规则。 使用与应用程序初始化功能集成的 URL 重写规则,可以在 IIS 继续在后台启动应用程序时为不同 URL 和虚拟路径提供不同类型的预生成的静态内容。

附录 - 设置示例 ASP.NET 应用程序

注意 - 以下步骤假定服务器已安装 IIS 8.0,并且已启用 ASP.NET 4.5,以便在 IIS 8.0 中使用。

解压缩示例应用程序

示例 ASP.NET 应用程序包含在以下 .zip 文件中:

将文件解压缩到 Web 服务器上的 wwwroot 文件夹。 例如,如果 Web 服务器在 C:\ 驱动器上安装了“默认网站”,请将文件的内容解压缩到 c:\inetpub\wwwroot\appinit

在 IIS 8.0 中创建一个应用程序

将“appinit”示例解压缩到文件系统后,需要将该文件夹配置为 IIS 8.0 中的 ASP.NET 应用程序。 以下屏幕截图显示了在 IIS 8.0 中配置为应用程序的 appinit 示例应用程序。 另请注意,应用程序会被分配到“.NET v4.5”应用程序池。

Screenshot of the I I S Manager's Advanced Settings menu.The sample appication and application pool are highlighted.

安装 URL 重写模块

示例应用程序使用 URL 重写模块与应用程序初始化功能进行高级集成。 需要在服务器上安装 URL 重写模块;可以从以下位置下载它:https://www.iis.net/downloads/microsoft/url-rewrite

配置 URL 重写模块

在 Web 服务器上安装 Url 重写模块后,需要修改 IIS applicationHost.config 文件,以允许使用应用程序初始化功能支持的 SKIP_MANAGED_MODULES 服务器变量。

在文本编辑器(如记事本)中打开计算机范围的 applicationHost.config 文件。 例如,如果在 C:\ 驱动器上安装操作系统,则 applicationHost.config 文件位于 C:\Windows\System32\inetsrv\config

向下滚动文件并找到安全部分。 本部分以 Xml 元素开头:<security>。

在<security>元素之前,键入以下 Xml 元素:

<rewrite>
  <allowedServerVariables>
    <add name="SKIP_MANAGED_MODULES" />
  </allowedServerVariables>
</rewrite>

保存对 applicationHost.config 文件的更改。