在 Windows Vista 和 Windows Server 2008 上将 ASP.NET 1.1 升级到 IIS 7.0

作者:IIS 团队

介绍

对于迁移到 Windows Vista™ 或更高版本 Windows 操作系统的 ASP.NET 应用程序开发人员,IIS 7.0 及以上版本相比早期 IIS 版本具有很大的进步。 IIS 集成模式提供了更高的安全性和新的应用程序可能性,以及其他改进。

大多数迁移到 Windows Vista 的开发人员都会从 Microsoft Windows® XP 操作系统升级到 Windows Vista,并在此过程中升级他们的 ASP.NET 应用程序。 或者,他们在 Windows Vista 上安装在其他 Windows 操作系统上开发的 ASP.NET 应用程序。

本文详细介绍了使应用程序在新操作系统上运行而必须执行的重要的安装后和升级后配置步骤。 其中介绍了经典模式和 IIS 集成模式之间影响 ASP.NET 应用程序的更改,以及如何解决这些已知问题。

IIS 7.0 及以上版本的其中一项重大改进是集成管道功能,该功能可使 Web 应用程序使用来自托管或非托管代码应用程序的单一请求处理管道。 此外,新的管道模型还减少了同一功能的两个独立实现所产生的冗余行为。

例如,在以前的版本中,IIS 和 ASP.NET 实现了单独的请求管道,这些管道不共享对事件和处理程序模块的访问权限。 身份验证在每个管道中独立进行。 在新模型中,IIS 和 ASP.NET 只需进行一次身份验证。

这种集成的其他优势还包括:

  • ASP.NET 服务,如与 IIS 内容类型(如静态和传统 ASP 页面)配合使用的 Forms 身份验证和角色。
  • 使用托管代码和 ASP.NET 管道模块扩展 IIS 功能,而不是仅使用 ISAPI 扩展或 CGI。
  • 集成事件跟踪和错误日志功能,简化故障排除。
  • 在 ASP.NET 和 IIS 之间共享应用程序配置。

本文探讨了从早期版本的 IIS 迁移到 IIS 7.0 及以上版本的 ASP.NET 应用程序的兼容性问题,并特别关注了从经典模式过渡到在集成模式下使用集成管道的差异。

有关 ASP.NET 与 IIS 集成的功能和优势的完整概述,请参阅文章 ASP.NET 与 IIS 7.0 及以上版本的集成

从早期版本的 IIS 升级到 Windows Vista

下面的图表显示了 IIS 7.0 在 Windows Vista 可用版本上的可用性:

Windows Vista 版本 IIS 7.0 可用性
家庭基础版 N
家庭高级版 Y
企业 Y
旗舰版 Y

Windows Vista 上的 ASP.NET 升级方案

下表简要概括了从早期版本的 Windows 操作系统上的 ASP.NET 到 Windows Vista 上的 ASP.NET 的支持升级路径。 如发现问题,请参阅后续各节,了解有关升级限制的更多信息。

下表还显示,无法从服务器操作系统版本升级到客户机操作系统版本。 相反,必须在当前安装了服务器操作系统的计算机上执行 Vista 的全新安装。

操作系统 IIS 版本 .NET Framework 版本 升级到 Windows Vista/IIS 7.0 时的注意事项
Windows 2000 Server IIS 5.0 1.0, 1.1, 2.0 无法升级到 Windows Vista。
Windows 2000 Professional IIS 5.0 1.0, 1.1, 2.0 需要安装 OS。
Windows Server 2003 IIS 6.0 1.0, 1.1, 2.0 无法升级到 Windows Vista。
Windows XP 家庭版 空值 1.0, 1.1, 2.0 Windows XP 家庭版不包含 IIS。 用户可能会决定在 Windows Vista 上安装 IIS 7.0 或以上版本。
Windows XP Professional IIS 5.1 1.0 Windows Vista 不支持 .NET Framework 1.0。 ASP.NET 1.0 应用程序必须至少升级到 ASP.NET 1.1(推荐 ASP.NET 2.0)。
1.1 升级后需要手动配置(请参阅本文后面的部分)。
2.0 升级后,必须在 IIS 设置选项中选择 ASP.NET,才能以集成模式配置 ASP.NET 2.0。
Windows XP 平板电脑版 IIS 5.1 1.0 Windows Vista 不支持 .NET Framework 1.0。 ASP.NET 1.0 应用程序必须至少升级到 ASP.NET 1.1(推荐 ASP.NET 2.0)。
1.1 升级后需要手动配置(请参阅本文后面的部分)。
2.0 升级后,必须在 IIS 设置选项中选择 ASP.NET,才能以集成模式配置 ASP.NET 2.0。
Windows XP 专业版 (x64) IIS 5.1 1.1、2.0 需要全新安装操作系统。

安装后应用程序配置

安装或升级到 Windows Vista 后,用户必须立即执行额外的配置步骤,以使应用程序能够运行。 安装后配置取决于每个应用程序使用的 ASP.NET 版本。

配置 ASP.NET 1.1 应用程序

在安装 .NET Framework 1.1 之前(如果运行 ASP.NET 1.1 应用程序,则需要安装该框架),用户必须执行以下两个步骤来启用 ASP.NET 应用程序:

过程

运行 ASP.NET 应用程序的每个 IIS 应用程序池必须使用与应用程序所用 ASP.NET 版本相匹配的 .NET Framework 版本进行明确配置。 每个应用程序池只能运行一个 ASP.NET 版本,因此每个 ASP.NET 版本必须使用单独的应用程序池。

在 IIS 管理器控制台中,打开“应用程序池”,然后右键单击一个应用程序池并选择“基本设置”。 在图 1 所示的“编辑应用程序池”对话框中,选择与应用程序池中配置的应用程序相匹配的 .NET Framework 版本,然后单击“确定”。

Screenshot of the Edit Application Pool dialog box with selected dot N E T Framework selected.

图 1:编辑应用程序池设置

在经典模式下使用 ASP.NET 1.1

ASP.NET 1.1 在经典模式下运行时使用 IIS ISAPI 扩展,这是 ASP.NET 安装或升级后的默认设置(注意,ASP.NET 2.0 也可以在 Windows Vista 上以集成模式运行,该模式不需要 ISAPI 扩展)。

必须使用 IIS 管理控制台中的 ISAPI 和 CGI 限制配置,明确允许应用程序使用的 ASP.NET 版本运行。 打开 IIS 管理器,然后选择“ISAPI 和 CGI 限制”。 在“ISAPI 和 CGI 限制”页中,选择“限制”列中设置为“不允许”的每个 ASP.NET 版本,然后单击页面右侧的“允许”链接,将设置更改为“允许”。

图 2 显示了“ISAPI 和 CGI 限制”页的示例,其中选择了用于 ASP.NET 1.1 的 Aspnet_isapi.dll 程序集的版本。 在该图中,此 ISAPI 扩展的设置必须从“不允许”更改为“允许”。

Screenshot of the I S A P I and C G I Restrictions page.

图 2:ISAPI 和 CGI 限制列表

配置 ASP.NET 2.0 应用程序

在安装 Windows Vista 期间会安装 .NET Framework 2.0,因此安装后服务器上已存在 ASP.NET 2.0。 不过,要在 Vista 上完成 ASP.NET 2.0 应用程序的 ASP.NET 配置,用户必须执行以下两个步骤:

步骤 1

从 Windows Vista 包管理器(控制面板\程序和功能\打开或关闭 Windows 功能),选择 ASP.NET(如图 3 所示),然后单击“确定”。

注意

如果在此步骤之前计算机上已经安装了 ASP.NET,以这种方式选择 ASP.NET 可确保完成其他配置步骤。

Screenshot of the Windows Features pane with the A S P dot Net development feature selected in the expanded menu.

图 3:Windows Vista 安装 - Windows 功能

步骤 2

运行 ASP.NET 应用程序的每个 IIS 应用程序池必须使用与应用程序所用 ASP.NET 版本相匹配的 .NET Framework 版本进行明确配置。 每个应用程序池只能运行一个 ASP.NET 版本,因此每个 ASP.NET 版本必须使用单独的应用程序池。

在 IIS 管理器中,打开“应用程序池”,然后右键单击一个应用程序池并选择“基本设置”。 在图 4 所示的“编辑应用程序池”对话框中,选择与应用程序池中配置的应用程序相匹配的 .NET Framework 版本,然后单击“确定”。

Screenshot of Edit Application Pool dialog box with selected dot N E T Framework highlighted.

图 4:应用程序池和集成模式

应用程序池设置

将早期版本的 Windows 操作系统上的 ASP.NET 应用程序升级到 Windows Vista 时,应用程序会根据 IIS 应用程序隔离设置配置到应用程序池中,如下所示:

升级前的 IIS 隔离配置 IIS 应用程序池 IIS 应用程序池标识
低 AppPool NT AUTHORITY\NETWORK SERVICE
中 AppPool IWAM_<计算机名称>
应用程序配置到与应用程序名称匹配的应用程序池中 IWAM_<计算机名称>

Windows Vista 不支持 ASP.NET v1.0

Windows Vista 不支持 .NET Framework 1.0,因此 ASP.NET 1.0 应用程序必须至少升级到 ASP.NET 1.1。 强烈建议将 ASP.NET 1.0 应用程序升级到 ASP.NET2.0,以利用 ASP.NET 后续版本中更佳的性能和可维护性功能。

HTTP 处理程序

在 Windows Vista 上升级到 IIS 7.0 及以上版本时,只有在全局级别配置的预设 HTTP 处理程序才会升级。 不会升级在站点级别配置的处理程序。

并行支持

可以在 IIS 上并行运行在不同版本 ASP.NET(例如 1.1 和 2.0)上开发的应用程序。 必须将应用程序配置到 IIS 应用程序池。 该池必须针对开发应用程序的 ASP.NET 版本进行配置。 每个应用程序池只能配置一个 ASP.NET 版本。

.NET Framework 1.1 要求在 64 位 Windows Vista 上进行 WoW 64 配置

如果在 64 位版本的 Windows Vista 上安装了 .NET Framework 1.1,则 ASP.NET 无法正确设置。 在 64 位版本的 Windows Vista 上安装 .NET Framework 1.1 后,必须使用 IIS 管理工具手动配置应用程序,以便在全局级别使用 WOW 64 运行。

配置应用程序使用的管道模式

IIS 配置为对新应用程序使用新的集成模式。 这是默认行为。 管道模式通过应用程序池设置进行配置。 使用以下其中一种方法更改这些设置:

  • IIS 管理工具
  • APPCMD.EXE 命令行工具
  • 使用文本编辑器编辑应用程序配置文件

如果要将现有计算机升级到 IIS 7.0 或以上版本,应用程序默认配置为以经典模式运行。 经典模式为在早期版本的 IIS 中实现 HTTP 管道具有特定依赖项的应用程序提供兼容性。

但是,如果要将现有应用程序导入运行 IIS 7.0 及以上版本的计算机,并复制网站,则使用的管道模式由应用程序配置为在其中运行的应用程序池的设置决定。

例如,如果将应用程序复制到计算机,并将其配置为在默认应用程序池中运行,那么它将使用该应用程序池的设置运行,默认情况下,该设置被配置为集成模式。 要更改应用程序的管道模式,可以更改“默认应用程序池”设置,也可以创建具有所需设置的新应用程序池。

有关如何配置现有应用程序以使用集成模式的更多信息,请参阅 ASP.NET 与 IIS 7.0 及以上版本的集成一文中的“将 ASP.NET 应用程序迁移到 IIS 7.0 及以上版本集成模式”部分。 其中提供了更改应用程序配置设置的说明。

兼容性

根据早期版本的 IIS 开发的 ASP.NET 管道模块,后来配置为使用 IIS 7.0 及以上版本的集成模式时,可能会出现行为差异或其他兼容性问题。 造成这些问题的原因是早期 IIS 版本的管道与 IIS 7.0 及以上版本的模块化设计以及集成 HTTP 管道之间的架构差异。

本文其余各节将介绍应用程序可能遇到的潜在兼容性问题,并包括建议的解决方法。 如果建议的解决方法不切实际,可将应用程序配置为在经典模式下运行,以避免兼容性问题。

集成模式和经典模式之间的已知差异

下面提供了两种模式之间的已知问题列表。 请仔细阅读此列表。

在集成模式下,不会调用 Application_OnError 来处理 HttpApplication::Init 中出现的异常

在集成模式下,无法使用 Application.Error 事件拦截应用程序或模块初始化过程中出现的异常。

此外,使用 Server.ClearError 从错误中恢复的应用程序无法在应用程序初始化期间清除错误。 这是为了防止应用程序在初始化过程中忽略错误。 记录每次异常发生时的错误信息的应用程序将无法记录应用程序初始化过程中发生的错误,尽管这些错误是通过 Web 事件和 HTTP 响应报告的。

如果应用程序需要在初始化过程中执行此类异常处理,则必须在经典模式而非集成模式下运行。

在集成模式下,EndRequest 中的 Server.ClearError 无法清除异常消息

在集成模式下,如果在请求处理的早期阶段出现异常,在 EndRequest 中调用 Server.ClearError 不会清除异常响应。 在 EndRequest 中清除异常消息的应用程序无法从响应中移除异常输出。

如果应用程序需要在 EndRequest 期间执行此类异常处理,则必须在经典模式而非集成模式下运行。

集成模式应用程序可在异常格式化并写入响应后,在 EndRequest 中写入响应

在集成模式下,可以写入并显示异常发生后写入的其他响应。

经典模式下不会出现这种情况。 如果在请求过程中发生错误,且应用程序在异常发生后在 EndRequest 中写入了响应,则会显示在 EndRequest 中写入的响应信息。 这只会影响包含未处理异常的请求。

为避免在出现异常后写入响应,应用程序必须在写入响应前检查 HttpContext.Error 或 HttpResponse.StatusCode。

在集成模式下,当响应为空时,ASP.NET 不再抑制内容类型

在集成模式下,即使响应为空,ASP.NET 处理程序也会在模块显示设置时生成 Content Type 标头。 某些应用程序会为空响应生成内容类型。 如果需要,可修改应用程序,通过将 Content Type 标头设置为 NULL 来明确移除该标头。

Forms 身份验证中的不同 Windows 身份

当应用程序使用 Forms 身份验证并允许匿名访问时,集成模式身份与经典模式身份有以下不同:

  • 已填充 ServerVariables["LOGON_USER"]。
  • Request.LogognUserIdentity 使用 [NT AUTHORITY\NETWORK SERVICE] 帐户的凭据,而不是 [NT AUTHORITY\INTERNET USER] 帐户。

出现这种行为的原因是,在集成模式下,身份验证是在一个阶段内完成的。 相反,在经典模式下,首先使用匿名访问在 IIS 中进行身份验证,然后使用 Forms 身份验证在 ASP.NET 中进行身份验证。 因此,身份验证的结果总是一个用户 - Forms 身份验证用户。 AUTH_USER/LOGON_USER 返回同一个用户,因为 IIS 和 ASP.NET 之间的 Forms 身份验证用户凭据是同步的。

其副作用是,LOGON_USER、HttpRequest.LogonUserIdentity 和冒充不再能访问 IIS 使用经典模式进行身份验证的匿名用户凭据。

默认 Authentication_OnAuthenticate 事件不会在集成模式下引发

在集成模式下,不再引发 DefaultAuthenticationModule.Authenticate 事件。 在经典模式下,当未进行身份验证时会引发该事件。 在集成模式下,身份验证模式设置为“无”并订阅 DefaultAuthentication.Authenticate 事件的应用程序将收到一个异常,指示集成模式下不支持此功能。 依赖这种模式的身份验证方案将不起作用。

要解决此问题,集成模式应用程序可改为订阅 AuthenticateRequest。

在集成模式下,Request.RawUrl 包含调用 RewritePath 后的新查询字符串

在集成模式下,在对带有新查询字符串的 URL 调用 RewritePath 后,Request.RawUrl 属性会包含该新的查询字符串。 在经典模式下,它包含旧的查询字符串。

要解决此问题,请重写应用程序,使其不依赖于旧的行为。

Windows Vista 不支持 Passport Network 凭据身份验证

Passport Network 凭据功能已从 Windows Vista 和 Microsoft Windows Server® 2008 操作系统中移除,因此 Passport Network 凭据身份验证应用程序默认无法在 ISAPI 或集成模式下运行。

PassportAuthentication 模块不是集成管道的一部分

在集成模式下,ASP.NET Passport 身份验证模块默认从管道中移除。 如果应用程序使用了该模块,可将其重新添加到管道中。 如上所述,基础 Passport Network 凭据功能已从 Windows Vista 和 Microsoft Windows Server 2008 中移除,因此 Passport Network 凭据验证应用程序默认无法在 ISAPI 或集成模式下运行。

IIS 7.0 及以上版本会拒绝接受查询字符串中存在的大型有效 Forms 身份验证票证(长度 <= 4096 字节)

IIS 会拒绝包含大型无 Cookie ASP.NET 票证的请求,例如用于 Forms 身份验证、会话状态和匿名 ID 的票证总计超过 4096 字节。 出于安全考虑,这样可以防止使用大查询字符串的缓冲区溢出漏洞。 存储自定义数据或在 Forms 身份验证票证中使用超大用户名的应用程序可能会发现,由于查询字符串过大,请求会被拒绝。

要更改此行为,请在 IIS 请求筛选配置部分调整最大查询字符串大小。

在集成模式下,ASP.NET 请求超时会在请求过程中多次应用,从而延长请求的执行时间

在集成模式下,管道中的每个新转换都会重置托管请求执行超时。 这意味着,只要任何单次超时不超过为超时设置的最长时间,请求最多可使用(超时 *(模块通知数))。

速度较慢的请求可能不会中止,也可能需要更长的时间才会中止,这取决于 ASP.NET 模块的数量以及这些模块的合并效果如何。 减少超时时间的设置长度可避免这种行为。

跟踪设置不会传输到 Server.Transfer 目标页

集成模式不支持将跟踪设置传输到 Server.Transfer 操作的目标。

方法 Httpcontext.Current.Response.Write() 无法在 Application_Onstart() 中运行

在集成模式下,应用程序不能在 Application_Onstart() 方法中调用 Http.Current.Response.Write()。

在 PostAuthenticateRequest 之前访问 HttpRequest.LogonUserIdentity 时会引发异常

在集成模式下,如果在 PostAuthenticateRequest 之前访问 HttpRequest.LogonUserIdentity 属性,则会引发异常。 如果模块在 PostAuthenticateRequest 之前访问该属性,则会引发异常。

要避免这种行为,请不要在应用程序中访问该属性,或者在 PostAuthenticateRequest 完成后再访问该属性。

在集成模式下,当禁用匿名身份验证时,ASP.NET 模块将收到对 IIS 7.0 及以上版本的第一个未经身份验证的请求

在集成模式下,当使用匿名身份验证以外的 IIS 身份验证方案时,ASP.NET 模块会在 BeginRequest 和 AuthenticateRequest 阶段看到客户端发出的第一个不包含所需凭据的请求。

相比之下,在经典模式下,ASP.NET 应用程序不会看到这样的请求,因为在 ASP.NET 有机会处理之前,IIS 就会以 401 挑战拒绝该请求。

这意味着 ASP.NET 模块将在 BeginRequest 和 AuthenticateRequest 阶段看到一个额外的请求。 该请求会出现在 Web 事件以及 BeginRequest 或 EndRequest 中的任何自定义日志中。

ASP.NET 在 PostAuthenticateRequest 之前无法冒充客户端身份

在集成模式下,如果使用应用程序的 Web.config 或在 Machine.config 中为应用程序启用了客户端冒充,则 ASP.NET 在 PostAuthenticateEvent 之前不会冒充客户端。

此外,启用客户端冒充功能后,在 BeginRequest 和 AuthenticateRequest 事件中运行的模块将以进程身份而不是已通过身份验证的用户身份执行。 这应该不成问题,因为由于尚未建立已通过身份验证的用户,模块很少在这些事件中访问资源。

但是,如果已建立,就会使用进程身份来访问资源。

由于此更改可能会导致用户权限的提升,因此在启用客户端冒充时,IIS 会引发一个异常。 这表明应用程序应转入经典模式,或者如果可以确认在 BeginRequest 或 AuthenticateRequest 事件中访问了资源,则应关闭此错误。

当字符集和内容类型设置为空字符串时,不会生成 Content-Type 标头

当 Content-Type 标头明确设置为 String.Empty 时,HTTP.sys 不再生成该标头。 客户端依赖于空 Content-Type 标头的应用程序可能会受到此更改的影响。

在集成模式下,每个模块在执行下一个模块之前都会发生同步和异步事件

在集成模式下,在服务器转到下一个模块之前,每个模块都会发生同步和异步事件。

这与经典模式不同,在经典模式下,所有异步模块通知先执行,然后再执行所有同步通知。 除非依赖于排序(请参阅本文档其他位置的 PreSendRequestHeaders 和 PreSendRequestContent 反转模块的排序),否则应用程序不应产生任何影响。除非对排序有依赖性,否则不会对应用程序产生影响(请参阅本文档其他部分的“使用集成模式时,PreSendRequestHeaders 和 PreSendRequestContent 的模块顺序相反”)。

在集成模式下,在自定义 IHttpModule 中调用 ClearHeader 后,响应头会被移除

在集成模式下,调用 ClearHeaders 不会自动生成默认标头。 调用 ClearHeaders 将 .aspx 页面的标头返回默认状态的应用程序,会清除所有响应标头。

不支持在集成模式下同时使用 Windows 和 Forms 身份验证

在集成模式下,不支持将“冒充”设置为 true 和使用 Forms 身份验证,并会导致错误或不正确的行为。

在集成模式下,IIS 7.0 及以上版本始终拒绝在响应标头中添加新行(即使 ASP.NET enableHeaderChecking 设置为 false)

在集成模式下,如果尝试将响应标头设置为包含 \r 或 \n 的值,就会出现异常。 在经典模式下,该值默认为编码值,如果关闭了标头编码,将会传递该值。 出于安全考虑,应用程序不得尝试在标头值中写入未编码的新行。

每个模块的 PreSendRequestHeaders 和 PreSendRequestContent 事件将同时发生

在集成模式下,订阅 PreSendRequestHeaders 和 PreSendRequestContent 事件的模块会同时收到 PreSendRequestHeaders 和 PreSendRequestContent 事件的通知。

例如,如果模块 A 依赖于在 PreSendRequestHeaders 中首先运行的模块 B,然后才针对 PreSendRequestContent 运行模块 A,比如模块 B 修改了某些请求状态,而模块 A 依赖于该请求状态,那么应用程序就可能崩溃。

使用集成模式时,PreSendRequestHeaders 和 PreSendRequestContent 的模块顺序相反

在集成模式下,订阅 PreSendRequestHeaders 和 PreSendRequestContent 的模块将按其在节中出现的相反顺序收到通知。 如果有多个模块被配置为在上述任一事件中运行,而它们又共同依赖于事件顺序,那么这些应用程序就会受到此更改的影响。

要解决这些问题,可以更改模块在节中的顺序,或者在经典模式下运行应用程序。

在集成模式下,线程和队列设置将被忽略

在集成模式下,ASP.NET(而不是 IIS)在线程上处理请求,而不使用经典模式下的线程或队列语义。 由于这种差异,应用程序在集成模式下的吞吐量或压力行为可能与在经典模式下运行时不同。

如果在使用集成模式时遇到配置文件错误,IIS 而不是 ASP.NET 会生成错误消息

对于在集成模式下运行的应用程序,IIS 现在可以读取应用程序配置文件。 因此,如果在 Web.config 文件中发现畸形 XML 或文件中存在配置错误,IIS 始终会生成错误消息,而不是 ASP.NET。

由于 IIS 和 ASP.NET 以不同的格式写入错误,因此错误消息的格式会因应用程序是在集成模式还是经典模式下运行而有所不同。 下面是 IIS 生成的一种配置文件错误类型示例:内部服务器错误 配置错误:配置文件不是格式规范的 XML

在集成模式下,ASP.NET 应用程序必须在模块的 Init 调用期间订阅管道事件

使用 ASP.NET HTTP 管道的 ASP.NET 应用程序可以订阅管道外的应用程序事件。 但是,使用 IIS 集成模式管道的 ASP.NET 应用程序现在必须始终在模块的 Init() 方法期间订阅事件。 下面的示例展示了如何在 Init 中实现事件订阅:

Public void Init(httpApplication context)
{
    Context.AuthenticateRequest += new EventHandler(this.AuthenticateUser);
}

有关如何创建 IIS 模块的详细信息,请参阅使用 .NET 开发模块一文。

其他资源

有关在 Windows Vista 上升级到 IIS 7.0 及以上版本的详细信息,请参阅有关 Windows Vista 上的 IIS 7.0 应用程序兼容性的文章:Windows Vista 的兼容性和功能要求