ASP.NET 请求的处理逻辑可以概括为以下步骤: 当请求到达时,IIS 检查资源类型并调用 ASP.NET ISAPI 扩展。如果启用了默认的进程模型,aspnet_isapi 会将请求排队,并将请求分配给辅助进程。所有的请求数据都通过异步 I/O 发送。如果启用了 IIS 6 进程模型,请求将自动在辅助进程 (w3wp.exe) 中排队,此辅助进程用于处理应用程序所属的 IIS 应用程序池。IIS 6 辅助进程不了解 ASP.NET 和托管代码的任何情况,它只是处理 *.aspx 扩展并加载 aspnet_isapi 模块。当 ASP.NET ISAPI 在 IIS 6 进程模型中运行时,它的工作方式有所不同,仅在 w3wp.exe 辅助进程的上下文中加载 CLR。 收到请求后,ASP.NET 辅助进程将通知 ASP.NET ISAPI,它将为请求服务。通知通过同步 I/O 实现。之所以使用同步模型,是因为请求只有在 ISAPI 内部请求表中被标记为“executing”,辅助进程才能开始处理它。如果请求已经由特殊的辅助进程进行处理,则不能再将它指定到其他进程,除非原始进程已取消。
在辅助进程的上下文中执行请求。有时,辅助进程可能需要回调 ISAPI 以完成请求,也就是需要说枚举服务器变量。这种情况下,辅助进程将使用同步管道,因为这样可以保持请求处理逻辑的顺序。 完成后,响应被发送到打开了异步管道的 aspnet_isapi。现在,请求的状态变为“Done”,之后将从请求表中被删除。如果辅助进程崩溃,正在处理的所有请求仍将保持“executing”状态并持续一段时间。如果 aspnet_isapi 检测到辅助进程已取消,它将自动终止请求并释放所有相关的 IIS 资源。 以上说明是指默认的 ASP.NET 进程模型,即在 IIS 5.x 中运行的工作模型。IIS 6(Windows Server 2003 提供)的默认工作方式对 ASP.NET 进程模型也有影响。当集成在 IIS 6.0 中时,ASP.NET 1.1 会自动调整自己的工作方式以适应宿主环境。这时,不再需要使用 aspnet_wp 辅助进程,machine.config 文件中定义的某些配置参数也被忽略。从 ASP.NET 的角度来看,IIS 6 的最大改变是有关请求的一切都在 aspnet_isapi 的控制之下,且都处在 w3wp.exe 辅助进程的上下文中。辅助进程的帐户是为 Web 应用程序所属的应用程序池设置的帐户。默认情况下,该帐户是 NETWORKSERVICE—,它是一个内置的弱帐户,在功能上与 ASPNET 等价。 辅助进程受一个名为进程回收 (Recycling) 的功能的控制。进程回收具有 aspnet_isapi 功能,当现有进程消耗的内存太多、响应太慢或挂起时可以自动启动新进程。出现这种情况时,新请求将由新实例处理,新实例从而变成新的活动进程。但是,指定给旧进程的所有请求仍保持挂起状态。如果旧进程结束了挂起的请求并进入空闲状态,该进程即终止。如果辅助进程崩溃,或者由于其他原因停止处理请求,则所有挂起的请求将被重新指定给新进程。 尽管 ASP.NET ISAPI 和辅助进程是 ASP.NET 运行时结构的主要组成部分,但还有其他一些可执行文件也发挥着作用。下表列出了所有这些组件。 表 1:构成 ASP.NET 运行时环境的可执行文件名称 类型 帐户
aspnet_isapi.dll Win32 DLL(ISAPI 扩展) LOCAL SYSTEM
aspnet_wp.exe Win32 EXE ASPNET
aspnet_filter.dll Win32 DLL(ISAPI 筛选器) LOCAL SYSTEM
aspnet_state.exe Win32 NT Service ASPNET aspnet_filter.dll 组件是一个小的 Win32 ISAPI 筛选器,用来备份 ASP.NET 应用程序的无 Cookie 会话状态。在 Windows Server 2003 中,当启用 IIS 6 进程模型时,aspnet_filter.dll 还将筛选出 Bin 目录中对非可执行资源的请求。 aspnet_state.exe 的作用对 Web 应用程序更为重要,因为它用于管理会话状态。该项服务是可选的,可以用来在 Web 应用程序内存空间之外保存会话状态数据。该可执行文件是一种 NT 服务,既可以在本地运行,也可以远程运行。当该服务被激活后,可以将 ASP.NET 应用程序配置为将所有会话信息保存在此进程的内存中。一种类似的方案是提供更为可靠的数据存储方式,不受进程回收和 ASP.NET 应用程序故障的影响。该服务在 ASPNET 本地帐户下运行,但可以使用服务控制管理器 (Service Control Manager) 接口来配置它。 另一个应该介绍的可执行文件是 aspnet_regiis.exe,尽管严格来讲,它并不属于 ASP.NET 运行时结构。该实用程序可以用来配置环境,以在一台计算机上并行执行不同版本的 ASP.NET,还可用于维修 IIS 和 ASP.NET 损坏的配置。该实用程序的工作方式是更新存储在 IIS 配置数据库的根目录和子目录中的脚本映射。脚本映射是资源类型和 ASP.NET 模块之间的一种关联关系。最后,还可以使用该工具来显示已安装的 ASP.NET 版本的状态,执行其他配置操作,如授予对特定文件夹的 NTFS 权限、创建客户脚本目录。
在辅助进程的上下文中执行请求。有时,辅助进程可能需要回调 ISAPI 以完成请求,也就是需要说枚举服务器变量。这种情况下,辅助进程将使用同步管道,因为这样可以保持请求处理逻辑的顺序。 完成后,响应被发送到打开了异步管道的 aspnet_isapi。现在,请求的状态变为“Done”,之后将从请求表中被删除。如果辅助进程崩溃,正在处理的所有请求仍将保持“executing”状态并持续一段时间。如果 aspnet_isapi 检测到辅助进程已取消,它将自动终止请求并释放所有相关的 IIS 资源。 以上说明是指默认的 ASP.NET 进程模型,即在 IIS 5.x 中运行的工作模型。IIS 6(Windows Server 2003 提供)的默认工作方式对 ASP.NET 进程模型也有影响。当集成在 IIS 6.0 中时,ASP.NET 1.1 会自动调整自己的工作方式以适应宿主环境。这时,不再需要使用 aspnet_wp 辅助进程,machine.config 文件中定义的某些配置参数也被忽略。从 ASP.NET 的角度来看,IIS 6 的最大改变是有关请求的一切都在 aspnet_isapi 的控制之下,且都处在 w3wp.exe 辅助进程的上下文中。辅助进程的帐户是为 Web 应用程序所属的应用程序池设置的帐户。默认情况下,该帐户是 NETWORKSERVICE—,它是一个内置的弱帐户,在功能上与 ASPNET 等价。 辅助进程受一个名为进程回收 (Recycling) 的功能的控制。进程回收具有 aspnet_isapi 功能,当现有进程消耗的内存太多、响应太慢或挂起时可以自动启动新进程。出现这种情况时,新请求将由新实例处理,新实例从而变成新的活动进程。但是,指定给旧进程的所有请求仍保持挂起状态。如果旧进程结束了挂起的请求并进入空闲状态,该进程即终止。如果辅助进程崩溃,或者由于其他原因停止处理请求,则所有挂起的请求将被重新指定给新进程。 尽管 ASP.NET ISAPI 和辅助进程是 ASP.NET 运行时结构的主要组成部分,但还有其他一些可执行文件也发挥着作用。下表列出了所有这些组件。 表 1:构成 ASP.NET 运行时环境的可执行文件名称 类型 帐户
aspnet_isapi.dll Win32 DLL(ISAPI 扩展) LOCAL SYSTEM
aspnet_wp.exe Win32 EXE ASPNET
aspnet_filter.dll Win32 DLL(ISAPI 筛选器) LOCAL SYSTEM
aspnet_state.exe Win32 NT Service ASPNET aspnet_filter.dll 组件是一个小的 Win32 ISAPI 筛选器,用来备份 ASP.NET 应用程序的无 Cookie 会话状态。在 Windows Server 2003 中,当启用 IIS 6 进程模型时,aspnet_filter.dll 还将筛选出 Bin 目录中对非可执行资源的请求。 aspnet_state.exe 的作用对 Web 应用程序更为重要,因为它用于管理会话状态。该项服务是可选的,可以用来在 Web 应用程序内存空间之外保存会话状态数据。该可执行文件是一种 NT 服务,既可以在本地运行,也可以远程运行。当该服务被激活后,可以将 ASP.NET 应用程序配置为将所有会话信息保存在此进程的内存中。一种类似的方案是提供更为可靠的数据存储方式,不受进程回收和 ASP.NET 应用程序故障的影响。该服务在 ASPNET 本地帐户下运行,但可以使用服务控制管理器 (Service Control Manager) 接口来配置它。 另一个应该介绍的可执行文件是 aspnet_regiis.exe,尽管严格来讲,它并不属于 ASP.NET 运行时结构。该实用程序可以用来配置环境,以在一台计算机上并行执行不同版本的 ASP.NET,还可用于维修 IIS 和 ASP.NET 损坏的配置。该实用程序的工作方式是更新存储在 IIS 配置数据库的根目录和子目录中的脚本映射。脚本映射是资源类型和 ASP.NET 模块之间的一种关联关系。最后,还可以使用该工具来显示已安装的 ASP.NET 版本的状态,执行其他配置操作,如授予对特定文件夹的 NTFS 权限、创建客户脚本目录。
{
// 确定请求是否是回发 (postback)
IsPostBack = DeterminePostBackMode();// 触发 ASPX 源代码的 Page_Init 事件
PageInit();// 加载 ViewState,处理已发送的值。
if (IsPostBack) {
LoadPageViewState();
ProcessPostData();
} // 触发 ASPX 源代码的 Page_Load 事件
PageLoad();// 1) 再次处理已发送的值(当
// 动态创建控件时)
// 2) 将属性更改的服务器端事件提升为输入驱动的
// 控件(即复选框的状态改变)
// 3) 执行与回发事件相关的所有代码
if (IsPostBack) {
ProcessPostDataSecondTry();
RaiseChangedEvents();
RaisePostBackEvent();
} // 触发 ASPX 源代码的 Page_PreRender 事件
PreRender();// 将控件的当前状态保存到 ViewState 中
SavePageViewState();// 将页面内容呈现给 HTML
RenderControl(CreateHtmlTextWriter(Response.Output));
} 无论调用的资源类型如何,基于 HTTP 处理程序的模型是相同的。唯一随资源类型变化而变化的元素是处理程序。HttpApplication 对象负责查找应该使用哪种处理程序来处理请求。HttpApplication 对象还负责检测对动态创建的、表示资源的程序集(如 .aspx 页面或 .asmx Web 服务)所进行的更改。如果检测到更改,应用程序对象将确保编译并加载所请求的资源的最新来源。
<filedep name="c:\inetpub\wwwroot\vdir\sample.aspx" />
</preserve> 当然,只有在分析 filedep 文件的源代码以生成动态程序集时才创建该文件。对 filedep 文件所做的任何更改都会使程序集无效,在下一次请求时必须重新编译。需要注意的是,在 ASP.NET 架构的未来版本中,该实现过程可能会有较大改变。不论什么原因,只要您决定在当前应用程序中使用它,都必须十分小心。 由于更新而要为页面创建新的程序集时,ASP.NET 将验证是否可以删除旧的程序集。如果旧的程序集只包含修改后的页面的类,ASP.NET 将试图删除并替换该程序集,否则将在保留旧程序集的情况下创建一个新程序集。 在删除过程中,ASP.NET 可能会发现程序集文件已被加载并锁定。这种情况下,可以为旧程序集添加一个“.DELETE”扩展名,以将其重新命名。(注意,所有 Windows 文件都可以在使用过程中重新命名。)只要应用程序重新启动(例如,由于对某个应用程序文件如 global.asax 和 web.config 进行了更改),这些临时的 .DELETE 文件就将被删除。但在处理下一个请求时,ASP.NET 运行时不会删除这些文件。 请注意,默认情况下,在整个应用程序重新启动之前,每个 ASP.NET 应用程序最多可以重新编译 15 个页面,同时会损失一些会话和应用程序数据。当最近的编译次数超过了 <httpRuntime> 部分的 numRecompilesBeforeAppRestart 属性中设置的阈值时,将卸载 AppDomain,并重新启动应用程序。还要注意,在 .NET Framework 中,您无法卸载单个程序集。AppDomain 是可以从 CLR 卸载的最小的代码块。 小结 ASP.NET 应用程序有两大特征:进程模型和页面对象模型。ASP.NET 提前使用了 IIS 6.0 的一些功能,而 IIS 6.0 则是 Windows Server 2003 中提供的全新的、开创性的 Microsoft Web 信息服务。尤其值得一提的是,在独立的辅助进程中运行的 ASP.NET 应用程序,其行为与 IIS 6 中的所有应用程序相同。而且,尽管会出现运行时异常、内存泄露或程序错误,ASP.NET 运行时仍能自动回收辅助进程以保证实现卓越的性能。这种功能已成为 IIS 6.0 的系统功能。 在本文中,我概括介绍了默认的 ASP.NET 进程模型的基础知识,以及 IIS 级代码(ASP.NET ISAPI 扩展)和辅助进程之间的交互。同时,还介绍了与 IIS 6 进程模型之间的最新区别。