通配符脚本映射和 IIS 7 集成管道

作者:Ruslan Yakushev

IIS 7 及更高版本集成请求处理管道的一大好处是,所有良好且有用的 ASP.NET 功能都可用于网站上的任何类型的内容;而不仅仅适用于特定于 ASP.NET 的内容。 例如,ASP.NET 基于 SQL 的成员身份可用于保护静态文件和文件夹。 此外,ASP.NET 扩展性 API(例如 IHttpHandler 和 IHttpModule)可用于添加自定义模块和处理程序,甚至可针对非 ASP.NET 内容执行这些模块和处理程序

IIS 6 没有此级别的集成。 ASP.NET 作为 ISAPI 扩展插入到 IIS 6 中,默认情况下配置为仅处理映射到该扩展的请求,例如,ASP.NET 扩展将处理以“.aspx”结尾的所有请求。 对于希望能够使用 ASP.NET 功能来处理网站上所有其他内容的客户来说,这显然是一个很大的限制。 最常见的解决方法是使用“通配符脚本映射”。 本文介绍如何将在 IIS 6 中使用通配符脚本映射的应用程序迁移至 IIS 7 及更高版本。

假设已在 IIS 6 中将 ASP.NET 配置为使用通配符脚本映射来处理所有请求。 例如,你有一个用于 URL 重写的 ASP.NET 模块,并希望此模块处理无扩展名的 URL。

此通配符脚本映射配置通常在 IIS 6 管理器中完成,方法是打开 Web 服务器或网站的属性对话框,选择“主目录”选项卡,单击“配置”按钮,然后单击“通配符应用程序映射”的“插入”按钮

Screenshot of Application Configuration dialog box and Add and Edit Application Extension Mapping dialog box. Insert button on Application Configuration dialog box is highlighted.

现在,将应用程序迁移至 IIS 7 及更高版本时,你希望对其进行配置以实现与 ASP.NET 相同的行为。 可通过两种方法执行此操作:使用“经典”管道模式或使用“集成”管道模式

IIS 7 及更高版本的经典管道模式下的通配符脚本映射

使用经典管道模式时,ASP.NET 作为 ISAPI 扩展插入 IIS 请求处理管道,这与 IIS 6 中的方式完全相同。 事实上,如果打开 %WINDIR%\system32\inetsrv\config\applicationHost.config 文件并找到其中的 <handlers> 部分,则可以了解如何配置 IIS 以将 ASP.NET 特定请求映射到 aspnet_isapi.dll

<handlers accessPolicy="Read, Script">
  ...
  <add name="PageHandlerFactory-ISAPI-2.0" 
       path="*.aspx" verb="GET,HEAD,POST,DEBUG" 
       modules="IsapiModule" 
       scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" 
       preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
  ...
</handlers>

请注意处理程序映射的 preCondition 属性。 除此之外,此属性设置为“classicMode”,这可确保此处理程序映射仅在应用程序池配置为在经典模式下运行时生效

现在,如果要为在经典模式下运行的 ASP.NET 配置通配符映射,方法是在 IIS 管理器中选择“处理程序映射”,然后单击“添加通配符脚本映射...”操作。

Screenshot of Add Wildcard Script Map dialog box and Handler Mappings page. In the Actions pane to the right of Handler Mappings page, Add Wilcard Script Map is highlighted.

选择“aspnet_isapi.dll”作为可执行文件,并为该脚本映射指定一个有意义的名称,例如“ASP.NET-ISAPI-2.0-Wildcard”。 之后单击“确定”,然后在“添加通配符脚本映射”对话框中单击“是”。

Screenshot of Add Wildcard Script Map dialog and Add Wildcard Script Map dialog. In the Add Wildcard Script Map dialog the options Yes, No, and Cancel are shown.

接下来,单击“查看有序列表...”操作,切换到处理程序映射的有序列表视图,并将新创建的映射移至列表底部的 StaticFile 处理程序映射之前:

Screenshot of Handler Mappings feature page. At the bottom of the handler mappings list view, OPTIONS Verb Handler, A S P dot NET dash I S A P I dash two dot zero dash Wildcard, and Static File are all highlighted.

如果打开 web.config 文件并查看 <handlers> 部分,应会看到 ASP.NET 的通配符脚本映射位于 StaticFile 处理程序之前:

<handlers accessPolicy="Read, Script">
  ...
  <add name="ASP.NET-ISAPI-2.0-Wildcard"
     path="*" verb="GET,HEAD,POST,DEBUG"
     modules="IsapiModule"
     scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll"
     preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0" />
  <add name="StaticFile" 
     path="*" verb="*" 
     modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" 
     resourceType="Either" requireAccess="Read" />
</handlers>

通配符处理程序映射的相对顺序很重要:如果在“StaticFile”处理程序映射之后定义此处理程序映射,则“StaticFile”将处理所有请求,并且不会有任何请求到达 ASP.NET 通配符处理程序。

你可能已经知道,IIS 7 及更高版本中的 ASP.NET 通配符处理程序映射受到与 IIS 6 中相同的性能限制。 此类处理程序映射的问题是所有请求都由它处理,包括对静态文件的请求。 ASP.NET 静态文件处理程序不如本机 IIS 静态文件处理程序强大。 另外,ASP.NET 提供的静态文件不会被服务器缓存,也不会被 Web 浏览器缓存。 由于这些性能限制,建议使用 IIS 7 及更高版本集成管道来实现与 IIS 6 中的通配符映射相同的功能。

使用 IIS 7 及更高版本集成管道,而非通配符脚本映射

借助集成管道,ASP.NET 功能完全集成到 IIS 中的主请求处理中,这意味着所有 ASP.NET 功能现在都可用于任何类型的请求。 这有效地消除了对通配符处理程序映射的需求。 现在可使用现有的 ASP.NET 模块,并将它们应用于所有请求。

例如,假设你有一个用 ASP.NET 编写的 URL 重写模块。 在 IIS 6 上,此模块在 web.config 文件的 <system.web> 部分内注册,如下所示:

<system.Web>
  <httpModules>
    ...
    <add name="MyUrlRewrite" 
         type="SomeNamespace.MyModules.UrlRewrite, SomeNamespace.MyModules" />
    ...
  </httpModules>
</system.Web>

由于在 IIS 6 上,此模块仅针对对托管内容的请求执行,因此它仅适用于具有 .aspx 扩展名的 URL,例如 http://example.com/archive/2008/08/26/post-title.aspx。 如果希望它处理无扩展名的 URL,则必须为 ASP.NET 配置通配符脚本映射。 使用 IIS 7 及更高版本集成管道时,不再需要执行此操作。 为了使此模块适用于无扩展名的 URL,需要在 web.config 文件内的 <system.webServer> 部分中注册它,如下所示:

<system.webServer>
  <modules >
    ...
    <add name="MyUrlRewrite" 
         type="SomeNamespace.MyModules.UrlRewrite, SomeNamespace.MyModules" 
         preCondition="" />
    ...
  </modules>
<system.webServer>

请确保此处将 preCondition 属性留空,因为它会强制对所有请求执行此模块,而不仅仅是针对 ASP.NET 特定内容的请求。

以这种方式注册托管模块不会像使用通配符脚本映射那样对性能产生巨大影响。 即使为对 Web 应用程序的所有请求调用此模块,所有现有处理程序映射仍然有效,这意味着静态文件仍由本机 IIS 静态文件处理程序提供服务。 以这种方式注册模块的另一个好处是,现在它可应用于针对 PHP、ASP 或任何其他动态页面的请求。 如果使用通配符脚本映射,则无法执行此操作。

最后要提到的是,还可以使用 <modules> 部分中名为 runAllManagedModulesForAllRequests 的属性

<system.webServer>
  <modules runAllManagedModulesForAllRequests="True" >
    ...
    <add name="MyUrlRewrite" 
         type="SomeNamespace.MyModules.UrlRewrite, SomeNamespace.MyModules" 
         preCondition="ManagedHandler" />
    ...
  </modules>
<system.webServer>

此属性强制 IIS 忽略 preCondition="managedHandler" 属性,因此将为 Web 应用程序的所有请求调用所有托管模块。