http://www.cnblogs.com/qianlifeng/archive/2010/12/16/1908568.html
https://msdn.microsoft.com/zh-cn/library/ms178473(v=vs.100).aspx
http://www.cnblogs.com/suizhouqiwei/archive/2012/08/15/2637775.html
IIS 7.0 的 ASP.NET 应用程序生命周期概述
更新:2007 年 11 月
本主题介绍在 IIS 7.0 集成模式下运行以及与 IIS 7.0 或更高版本一起运行的 ASP.NET 应用程序的应用程序生命周期。IIS 7.0 还支持经典模式,其行为类似于在 IIS 6.0 中运行的 ASP.NET。有关更多信息,请参见 IIS 5.0 和 6.0 的 ASP.NET 应用程序生命周期概述。
IIS 7.0 集成管道是一种统一的请求处理管道,它同时支持本机代码和托管代码模块。实现 IHttpModule 接口的托管代码模块可访问该请求管道中的所有事件。例如,托管代码模块可用于 ASP.NET 网页(.aspx 文件)和 HTML 页(.htm 或 .html 文件)的 ASP.NET Forms 身份验证。即使 IIS 和 ASP.NET 将 HTML 页视为静态资源,情况也是如此。有关 IIS 7.0 集成模式的更多信息,请参见 ASP.NET Integration with IIS7(将 ASP.NET 与 IIS7 集成)。
本主题包含以下部分:
在 IIS 7.0 集成模式下的请求会经历几个阶段,类似于在 IIS 6.0 中对 ASP.NET 资源的请求所经历的阶段。但是,在 IIS 7.0 中,这些阶段包含多个额外的应用程序事件,如 MapRequestHandler、MapRequestHandler 和 MapRequestHandler 事件。
IIS 7.0 和 IIS 6.0 的处理阶段之间的主要区别在于 ASP.NET 如何与 IIS 服务器集成。在 IIS 6.0 中,有两个请求处理管道。一个管道用于本机代码 ISAPI 筛选器和扩展组件。另一个管道用于托管代码应用程序组件,如 ASP.NET。在 IIS 7.0 中,ASP.NET 运行时与 Web 服务器集成,这样就有了一个针对所有请求的统一的请求处理管道。对于 ASP.NET 开发人员,集成管道有以下益处:
集成管道引发由 HttpApplication 对象公开的所有事件,这使现有 ASP.NET HTTP 模块可在 IIS 7.0 集成模式下工作。
在 Web 服务器级别、网站级别或 Web 应用程序级别,都可配置本机代码和托管代码模块。这包括用于会话状态、Forms 身份验证、配置文件以及角色管理的内置 ASP.NET 托管代码模块。此外,可以为所有请求启用或禁用托管代码模块,无论请求是否针对 ASP.NET 资源(如 aspx 文件)。
可以在管道中的任何阶段调用托管代码模块。这包括在对请求进行任何服务器处理之前,在所有服务器处理都已发生之后,或者两者间的任何阶段。
可以通过应用程序的 Web.config 文件注册模块,也可以启用或禁用模块。
下面的插图演示应用程序的请求管道的配置。该示例包括以下内容:
Anonymous 本机代码模块和 Anonymous 托管代码模块(对应于 FormsAuthenticationModule)。这些模块都已配置,并在请求的Authentication阶段调用。
Basic 本机代码模块和 Windows 托管代码模块(对应于 WindowsAuthenticationModule)。它们虽然显示,但并没有为应用程序进行配置。
在 Execute handler 阶段,会调用处理程序(应用范围为 URL 的模块)以构造响应。对于 .aspx 文件,使用 PageHandlerFactory 处理程序来响应请求。对于静态文件,本机代码 StaticFileModule 模块响应请求。
Trace 本机代码模块。此模块虽然显示,但并没有为应用程序进行配置。
Custom module 托管代码类。该类在 Log request 阶段中调用。
有关从早期版本的 IIS 迁移到 IIS 7.0 的 ASP.NET 应用程序的已知兼容性问题的信息,请参见 Upgrading ASP.NET Applications to IIS 7.0: Differences between IIS 7.0 Integrated Mode and Classic mode(将 ASP.NET 应用程序升级到 IIS 7.0:IIS 7.0 集成模式和经典模式之间的区别)中的“Known Differences Between Integrated Mode and Classic Mode”(集成模式和经典模式之间的已知区别)部分。
下表列出了在 IIS 7.0 集成模式下运行的 ASP.NET 应用程序生命周期的各个阶段。
阶段 |
说明 |
---|---|
发出一个对应用程序资源的请求。 |
ASP.NET 应用程序的生命周期以浏览器向 Web 服务器发送请求为起点。 在 IIS 7.0 经典模式下以及在 IIS 6.0 中,ASP.NET 请求管道与 Web 服务器管道分离。模块仅应用于路由到 ASP.NET ISAPI 扩展的请求。如果请求的资源类型的文件扩展名未显式映射到 ASP.NET,则不会为该请求调用 ASP.NET 功能,因为 ASP.NET 运行时没有处理该请求。 而在 IIS 7.0 集成模式下,由一个统一的管道处理所有请求。当集成管道收到请求时,该请求将经历所有请求共有的一些阶段。这些阶段由 RequestNotification 枚举表示。所有请求都可以配置为使用 ASP.NET 功能,因为该功能封装在可以访问请求管道的托管代码模块中。例如,即使 .htm 文件扩展名未显式映射到 ASP.NET,对 HTML 页的请求仍会调用 ASP.NET 模块。这使您能对所有资源使用 ASP.NET 身份验证和授权。 |
统一管道接收对应用程序的第一个请求。 |
当统一管道接收对应用程序中的任何资源的第一个请求时,将为 ApplicationManager 类创建一个实例,该实例就是处理请求的应用程序域。应用程序域提供了应用程序之间全局变量的分离,并且使每个应用程序能够单独卸载。在应用程序域中,将为HostingEnvironment 类创建一个实例,该实例提供对有关应用程序的信息(如存储该应用程序的文件夹的名称)的访问。 在第一个请求期间,如果需要,将对应用程序中的*项进行编译,其中包括 App_Code 文件夹中的应用程序代码。可以根据本主题后面的 IIS 7.0 中的托管代码模块中的说明,在 App_Code 文件夹中包含自定义模块和处理程序。 |
将为每个请求创建响应对象。 |
在创建了应用程序域并对 HostingEnvironment 对象进行了实例化之后,将创建并初始化应用程序对象,如HttpContext、HttpRequest 和 HttpResponse。HttpContext 类包含特定于当前应用程序请求的对象,如 HttpRequest 和HttpResponse 对象。HttpRequest 对象包含有关当前请求的信息,包括 Cookie 和浏览器信息。HttpResponse 对象包含发送到客户端的响应,其中包括所有呈现的输出和 Cookie。 下面是 IIS 6.0 和 IIS 7.0(在集成模式下,与 .NET Framework 3.0 或更高版本一起运行)之间的某些关键差异:
|
将HttpApplication 对象分配给请求 |
初始化所有应用程序对象之后,将通过创建 HttpApplication 类的实例来启动应用程序。如果应用程序有 Global.asax 文件,则 ASP.NET 会创建从 HttpApplication 类派生的 Global.aspx 类的实例。然后使用该派生类来表示应用程序。
说明:
第一次在应用程序中请求 ASP.NET 页或进程时,将创建 HttpApplication 类的一个新实例。不过,为了尽可能提高性能,可对多个请求重复使用 HttpApplication 实例。
加载哪些 ASP.NET 模块(如 SessionStateModule)取决于应用程序从父应用程序继承的托管代码模块。这还取决于在应用程序的 Web.config 文件的配置节中配置了哪些模块。在应用程序的 Web.config 的 system.webServer 节中的 modules 元素中添加或移除模块。有关更多信息,请参见 如何:为 IIS 7.0 配置 <system.webServer> 节。 |
由HttpApplication 管线处理请求。 |
在处理请求时,HttpApplication 类会执行下列任务。这些事件对于希望在引发关键请求管道事件时运行代码的网页开发人员很有用。如果是在开发自定义模块,并且希望对发往管道的所有请求都调用该模块,则这些事件也很有用。自定义模块实现IHttpModule 接口。在 IIS 7.0 集成模式下,必须在模块的 Init 方法中注册事件处理程序。
|
Global.asax 文件在 IIS 7.0 中的集成模式下的使用与在 IIS 6.0 的 ASP.NET 中的使用有诸多类似。有关更多信息,请参见 IIS 5.0 和 6.0 的 ASP.NET 应用程序生命周期概述中的“生命周期事件和 Global.asax 文件”一节。
其中一个区别是:您可以为 MapRequestHandler、LogRequest 和 PostLogRequest 事件添加处理程序。对于在 IIS 7.0 集成模式下运行并且与 .NET Framework 3.0 或更高版本一起运行的应用程序,可以支持这些事件。
可以在 Global.asax 文件中提供应用程序事件处理程序,以添加为 ASP.NET 处理的所有请求(例如对 .aspx 和 .axd 页的请求)执行的代码。但是,不会调用 Global.asax 文件中的处理程序代码来处理对非 ASP.NET 资源(如静态文件)的请求。若要运行为所有资源运行的托管代码,请创建一个实现 IHttpModule 接口的自定义模块。该自定义模块将会运行,以处理对应用程序中的资源的所有请求,即使资源处理程序不是 ASP.NET 处理程序。
可在 IIS 7.0 中配置并加载的 ASP.NET 托管代码模块包括下面这些:
若要配置 IIS 7.0 托管代码模块,可以使用以下方法之一:
使用 IIS 管理器。有关更多信息,请参见如何:打开 IIS 管理器。
使用 IIS 7.0 命令行工具 (Appcmd.exe)。有关更多信息,请参见 IIS 7.0 Command-Line Tool(IIS 7.0 命令行工具)。
编辑 IIS 7.0 基于 XML 的配置存储区。有关更多信息,请参见 IIS 7.0: IIS 7.0 Configuration Store(IIS 7.0:IIS 7.0 配置存储区)。
当 ASP.NET 托管代码模块(如 FormsAuthenticationModule 模块)配置为在 IIS 7.0 中加载时,它可以访问请求管道中的所有事件。这意味着所有请求都将通过该托管代码模块。对于 FormsAuthenticationModule 类,这意味着可以使用 Forms 身份验证来保护静态内容,即使这些内容并非由 ASP.NET 处理程序进行处理。
开发自定义托管代码模块
可使用实现 IHttpModule 接口的模块来扩展 ASP.NET 应用程序生命周期。实现 IHttpModule 接口的模块为托管代码模块。ASP.NET 和 IIS 7.0 的集成管道还可以通过本机代码模块扩展,这些内容不在本主题讨论范围内。有关本机代码模块以及有关通常如何配置模块的更多信息,请参见 IIS Module Overview(IIS 模块概述)。
可以将托管代码模块定义为应用程序的 App_Code 文件夹中的一个类文件。还可以将模块创建为一个类库项目,并编译该项目,然后将其添加到应用程序的 Bin 文件夹下。创建自定义模块后,必须在 IIS 7.0 中注册它。可以使用所述方法之一来管理 IIS 7.0 托管代码模块。例如,可以编辑应用程序的 Web.config 文件来向该应用程序注册此托管代码模块。有关注册此模块的示例,请参见演练:创建和注册自定义 HTTP 模块。
如果某个模块在应用程序的 App_Code 或 Bin 文件夹中定义,并且已在应用程序的 Web.config 文件中注册,则此模块仅为该应用程序调用。若要在应用程序的 Web.config 文件中注册模块,可以使用 system.webServer 节中的 modules 元素。有关更多信息,请参见 如何:为 IIS 7.0 配置 <system.webServer> 节。使用 IIS 管理器或 Appcmd.exe 工具进行更改,也将对应用程序的 Web.config 文件进行相应更改。
托管代码模块也可以在 IIS 7.0 配置存储区(ApplicationHost.config 文件)的 modules 元素中注册。在 ApplicationHost.config 文件中注册的模块具有全局范围,因为它们为所有由 IIS 7.0 承载的 Web 应用程序而注册。同样,在 ApplicationHost.config 文件的 globalModules 元素中定义的本机代码模块也具有全局范围。如果 Web 应用程序不需要全局模块,则可以将其禁用。
示例
下面的示例演示一个处理 LogRequest 和 PostLogRequest 事件的自定义模块。事件处理程序在模块的 Init 方法中注册。
using System;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI; // Module that demonstrates one event handler for several events.
namespace Samples
{
public class ModuleExample : IHttpModule
{
public ModuleExample()
{
// Constructor
}
public void Init(HttpApplication app)
{
app.LogRequest += new EventHandler(App_Handler);
app.PostLogRequest += new EventHandler(App_Handler);
}
public void Dispose()
{
}
// One handler for both the LogRequest and the PostLogRequest events.
public void App_Handler(object source, EventArgs e)
{
HttpApplication app = (HttpApplication)source;
HttpContext context = app.Context; if (context.CurrentNotification == RequestNotification.LogRequest)
{
if (!context.IsPostNotification)
{
// Put code here that is invoked when the LogRequest event is raised.
}
else
{
// PostLogRequest
// Put code here that runs after the LogRequest event completes.
}
} }
}
}
下面的示例演示如何在应用程序的 Web.config 文件中注册模块。在 configuration 节内部添加 system.webServer 配置节。
<system.webServer>
<modules>
<add name="ModuleExample" type="Samples.ModuleExample"/>
</modules>
</system.webServer>
有关如何创建和注册自定义模块的其他示例,请参见演练:创建和注册自定义 HTTP 模块。
IIS 5.0 和 6.0 的 ASP.NET 应用程序生命周期概述
更新:2007 年 11 月
本主题概述 ASP.NET 应用程序的生命周期,列出了重要的生命周期事件,并描述了您编写的代码将如何适应于应用程序生命周期。本主题中的信息适用于 IIS 5.0 和 IIS 6.0。有关 IIS 7.0 中的 ASP.NET 应用程序生命周期的信息,请参见 IIS 7.0 的 ASP.NET 应用程序生命周期概述。
在 ASP.NET 中,若要对 ASP.NET 应用程序进行初始化并使它处理请求,必须执行一些处理步骤。 此外,ASP.NET 只是对浏览器发出的请求进行处理的 Web 服务器结构的一部分。 了解应用程序生命周期非常重要,这样才能在适当的生命周期阶段编写代码,达到预期的效果。
下表描述了 ASP.NET 应用程序生命周期的各个阶段。
阶段 |
说明 |
---|---|
用户从 Web 服务器请求应用程序资源。 |
ASP.NET 应用程序的生命周期以浏览器向 Web 服务器(对于 ASP.NET 应用程序,通常为 IIS)发送请求为起点。 ASP.NET 是 Web 服务器下的 ISAPI 扩展。Web 服务器接收到请求时,会对所请求的文件的文件扩展名进行检查,确定应由哪个 ISAPI 扩展处理该请求,然后将该请求传递给合适的 ISAPI 扩展。 ASP.NET 处理已映射到其上的文件扩展名,如 .aspx、.ascx、.ashx 和 .asmx。
说明:
如果文件扩展名尚未映射到 ASP.NET,则 ASP.NET 将不会接收该请求。 对于使用 ASP.NET 身份验证的应用程序,理解这一点非常重要。 例如,由于 .htm 文件通常没有映射到 ASP.NET,因此 ASP.NET 将不会对 .htm 文件请求执行身份验证或授权检查。 因此,即使文件仅包含静态内容,如果希望 ASP.NET 检查身份验证,也应使用映射到 ASP.NET 的文件扩展名创建该文件,如采用文件扩展名 .aspx。
说明:
如果要创建服务于特定文件扩展名的自定义处理程序,必须在 IIS 中将该扩展名映射到 ASP.NET,还必须在应用程序的 Web.config 文件中注册该处理程序。有关更多信息,请参见 HTTP 处理程序和 HTTP 模块概述。
|
ASP.NET 接收对应用程序的第一个请求。 |
当 ASP.NET 接收到对应用程序中任何资源的第一个请求时,名为 ApplicationManager 的类会创建一个应用程序域。 应用程序域为全局变量提供应用程序隔离,并允许单独卸载每个应用程序。 在应用程序域中,将为名为 HostingEnvironment 的类创建一个实例,该实例提供对有关应用程序的信息(如存储该应用程序的文件夹的名称)的访问。 下面的关系图说明了这种关系: 如果需要,ASP.NET 还可对应用程序中的*项进行编译,其中包括 App_Code 文件夹中的应用程序代码。 有关更多信息,请参见本主题后面的“编译生命周期”。 |
为每个请求创建 ASP.NET 核心对象。 |
创建了应用程序域并对 HostingEnvironment 对象进行了实例化之后,ASP.NET 将创建并初始化核心对象,如HttpContext、HttpRequest 和 HttpResponse。 HttpContext 类包含特定于当前应用程序请求的对象,如 HttpRequest 和HttpResponse 对象。 HttpRequest 对象包含有关当前请求的信息,包括 Cookie 和浏览器信息。 HttpResponse 对象包含发送到客户端的响应,包括所有呈现的输出和 Cookie。 |
将HttpApplication 对象分配给请求 |
初始化所有核心应用程序对象之后,将通过创建 HttpApplication 类的实例启动应用程序。 如果应用程序具有 Global.asax 文件,则 ASP.NET 会创建 Global.asax 类(从 HttpApplication 类派生)的一个实例,并使用该派生类表示应用程序。
说明:
第一次在应用程序中请求 ASP.NET 页或进程时,将创建 HttpApplication 的一个新实例。 不过,为了尽可能提高性能,可对多个请求重复使用 HttpApplication 实例。
创建 HttpApplication 的实例时,将同时创建所有已配置的模块。 例如,如果将应用程序这样配置,ASP.NET 就会创建一个SessionStateModule 模块。 创建了所有已配置的模块之后,将调用HttpApplication 类的 Init 方法。 下面的关系图说明了这种关系: |
由HttpApplication 管线处理请求。 |
在处理该请求时将由 HttpApplication 类执行以下事件。 希望扩展 HttpApplication 类的开发人员尤其需要注意这些事件。
|
在应用程序的生命周期期间,应用程序会引发可处理的事件并调用可重写的特定方法。 若要处理应用程序事件或方法,可以在应用程序根目录中创建一个名为 Global.asax 的文件。
如果创建了 Global.asax 文件,ASP.NET 会将其编译为从 HttpApplication 类派生的类,然后使用该派生类表示应用程序。
HttpApplication 进程的一个实例每次只处理一个请求。 由于在访问应用程序类中的非静态成员时不需要将其锁定,这样可以简化应用程序的事件处理过程。 这样还可以将特定于请求的数据存储在应用程序类的非静态成员中。 例如,可以在 Global.asax 文件中定义一个属性,然后为该属性赋一个特定于请求的值。
通过使用命名约定 Application_event(如 Application_BeginRequest),ASP.NET 可在 Global.asax 文件中将应用程序事件自动绑定到处理程序。 这与将 ASP.NET 页方法自动绑定到事件(如页的 Page_Load 事件)的方法类似。 有关详细信息,请参见 ASP.NET 页生命周期概述。
Application_Start 和 Application_End 方法是不表示 HttpApplication 事件的特殊方法。 在应用程序域的生命周期期间,ASP.NET 仅调用这些方法一次,而不是对每个 HttpApplication 实例都调用一次。
下表列出在应用程序生命周期期间使用的一些事件和方法。 实际远不止列出的这些事件,但这些事件是最常用的。
事件或方法 |
说明 |
---|---|
Application_Start |
请求 ASP.NET 应用程序中第一个资源(如页)时调用。 在应用程序的生命周期期间仅调用一次 Application_Start 方法。 可以使用此方法执行启动任务,如将数据加载到缓存中以及初始化静态值。 在应用程序启动期间应仅设置静态数据。 由于实例数据仅可由创建的 HttpApplication 类的第一个实例使用,所以请勿设置任何实例数据。 |
Application_event |
在应用程序生命周期中的适当时候引发,请参见本主题前面的应用程序生命周期表中列出的内容。 Application_Error 可在应用程序生命周期的任何阶段引发。 由于请求会短路,因此 Application_EndRequest 是唯一能保证每次请求时都会引发的事件。 例如,如果有两个模块处理Application_BeginRequest 事件,第一个模块引发一个异常,则不会为第二个模块调用 Application_BeginRequest 事件。 但是,会始终调用 Application_EndRequest 方法使应用程序清理资源。 |
在创建了所有模块之后,对 HttpApplication 类的每个实例都调用一次。 |
|
在销毁应用程序实例之前调用。 可使用此方法手动释放任何非托管资源。 有关更多信息,请参见清理非托管资源。 |
|
Application_End |
在卸载应用程序之前对每个应用程序生命周期调用一次。 |
在第一次对应用程序发出请求时,ASP.NET 按特定顺序编译应用程序项。 要编译的第一批项称为*项。 在第一次请求之后,仅当依赖项更改时才会重新编译*项。 下表描述编译 ASP.NET *项的顺序。
Item |
Description |
---|---|
App_GlobalResources |
编译应用程序的全局资源并生成资源程序集。 应用程序的 Bin 文件夹中的任何程序集都链接到资源程序集。 |
App_WebResources |
创建并编译 Web 服务的代理类型。 所生成的 Web 引用程序集将链接到资源程序集(如存在)。 |
Web.config 文件中定义的配置文件属性 |
如果应用程序的 Web.config 文件中定义了配置文件属性,则生成一个包含配置文件对象的程序集。 |
App_Code |
生成源代码文件并创建一个或更多个程序集。 所有代码程序集和配置文件程序集都链接到资源和 Web 引用程序集(如果有)。 |
Global.asax |
编译应用程序对象并将其链接到所有先前产生的程序集。 |
在编译应用程序的*项之后,ASP.NET 将根据需要编译文件夹、页和其他项。 下表描述编译 ASP.NET 文件夹和项的顺序。
Item |
Description |
---|---|
App_LocalResources |
如果包含被请求项的文件夹包含 App_LocalResources 文件夹,则编译本地资源文件夹的内容并将其链接到全局资源程序集。 |
各个网页(.aspx 文件)、用户控件(.ascx 文件)、HTTP 处理程序(.ashx 文件)和 HTTP 模块(.asmx 文件) |
根据需要编译并链接到本地资源程序集和*程序集。 |
主题、主控页、其他源文件 |
在编译引用页时编译那些页所引用的各个主题、主控页和其他源代码文件的外观文件。 |
编译后的程序集缓存在服务器上并在后续请求时被重用,并且只要源代码未更改,就会在应用程序重新启动之间得到保留。
由于应用程序在第一次请求时进行编译,所以对应用程序的初始请求所花的时间会明显长于后续请求。 可以预编译应用程序以减少第一次请求所需的时间。 有关更多信息,请参见 如何:预编译 ASP.NET 网站。
Application Restarts(应用程序重新启动的次数)
修改 Web 应用程序的源代码将导致 ASP.NET 把源文件重新编译为程序集。 当修改应用程序中的*项时,应用程序中引用*程序集的其他所有程序集也会被重新编译。
此外,修改、添加或删除应用程序的已知文件夹中的某些类型的文件将导致应用程序重新启动。 下列操作将导致应用程序重新启动:
添加、修改或删除应用程序的 Bin 文件夹中的程序集。
添加、修改或删除 App_GlobalResources 或 App_LocalResources 文件夹中的本地化资源。
添加、修改或删除应用程序的 Global.asax 文件。
添加、修改或删除 App_Code 目录中的源代码文件。
添加、修改或删除配置文件配置。
添加、修改或删除 App_WebReferences 目录中的 Web 服务引用。
添加、修改或删除应用程序的 Web.config 文件。
当应用程序需要重新启动时,ASP.NET 将在重新启动应用程序域和加载新的程序集之前,从现有应用程序域和旧的程序集中为所有挂起的请求提供服务。
ASP.NET 应用程序生命周期可通过 IHttpModule 类进行扩展。 ASP.NET 包含若干实现 IHttpModule 的类,如 SessionStateModule 类。 您还可以自行创建实现 IHttpModule 的类。
如果向应用程序添加模块,模块本身会引发事件。通过使用 modulename_eventname 约定,应用程序可以在 Global.asax 文件中预订这些事件。 例如,若要处理 FormsAuthenticationModule 对象引发的 Authenticate 事件,可以创建一个名为 FormsAuthentication_Authenticate 的处理程序。
默认情况下,ASP.NET 中会启用 SessionStateModule 类。 所有会话事件自动命名为 Session_event,如 Session_Start。 每次创建新会话时都会引发 Start 事件。 有关更多信息,请参见ASP.NET 会话状态概述。