首页 > 代码库 > 【IHttpHandler】ASP.NET 生命周期

【IHttpHandler】ASP.NET 生命周期

对由 Microsoft? Internet 信息服务 (IIS) 处理的 Microsoft? ASP.NET 页面的每个请求都会被移交到 ASP.NET HTTP 管道。HTTP 管道由一系列托管对象组成,这些托管对象按顺序处理请求,并将 URL 转换为纯 HTML 文本。HTTP 管道的入口是 HttpRuntime 类。ASP.NET 结构为辅助进程中的每个 AppDomain 创建一个此类的实例。(请注意,辅助进程为每个当前正在运行的 ASP.NET 应用程序维护一个特定的 AppDomain。)

 

HttpRuntime 类从内部池中获取 HttpApplication 对象,并安排此对象来处理请求。HTTP 应用程序管理器完成的主要任务就是找到将真正处理请求的类。当请求 .aspx 资源时,处理程序就是页面处理程序,即从 Page 继承的类的实例。资源类型和处理程序类型之间的关联关系存储在应用程序的配置文件中。更确切地说,默认的映射集是在 machine.config 文件的 <httpHandlers> 部分定义的。但是,应用程序可以在本地的 web.config 文件中自定义自己的 HTTP 处理程序列表。以下这一行代码就是用来为 .aspx 资源定义 HTTP 处理程序的。

 

<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory"/>
 

扩展名可以与处理程序类相关联,并且更多是与处理程序工厂类相关联。在所有情况下,负责处理请求的 HttpApplication 对象都会获得一个实现 IHttpHandler 接口的对象。如果根据 HTTP 处理程序来解析关联的资源/类,则返回的类将直接实现接口。如果资源被绑定到处理程序工厂,则还需要额外的步骤。处理程序工厂类实现 IHttpHandlerFactory 接口,此接口的 GetHandler 方法将返回一个基于 IHttpHandler 的对象。

 

HTTP 运行时是如何结束这个循环并处理页面请求的?ProcessRequest 方法在 IHttpHandler 接口中非常重要。通过对代表被请求页面的对象调用此方法,ASP.NET 结构会启动将生成浏览器输出的进程。

 

真正的 Page 类

特定页面的 HTTP 处理程序类型取决于 URL。首次调用 URL 时,将构建一个新的类,这个类被动态编译为一个程序集。检查 .aspx 资源的分析进程的结果是类的源代码。该类被定义为命名空间 ASP 的组成部分,并且被赋予了一个模拟原始 URL 的名称。例如,如果 URL 的终点是 page.aspx,则类的名称就是 ASP.Page_aspx。不过,类的名称可以通过编程方式来控制,方法是在 @Page 指令中设置 ClassName 属性。

 

HTTP 处理程序的基类是 Page。这个类定义了由所有页面处理程序共享的方法和属性的最小集合。Page 类实现 IHttpHandler 接口。

 

在很多情况下,实际处理程序的基类并不是 Page,而是其他的类。例如,如果使用了代码分离,就会出现这种情况。代码分离是一项开发技术,它可以将页面所需的代码隔离到单独的 C# 和 Microsoft Visual Basic? .NET 类中。页面的代码是一组事件处理程序和辅助方法,这些处理程序和方法真正决定了页面的行为。可以使用 <script runat=server> 标记对此代码进行内联定义,或者将其放置在外部类(代码分离类)中。代码分离类是从 Page 继承并使用额外的方法的类,被指定用作 HTTP 处理程序的基类。

还有一种情况,HTTP 处理程序也不是基于 Page 的,即在应用程序配置文件的 <pages> 部分中,包含了 PageBaseType 属性的重新定义。

 

<pages PageBaseType="Classes.MyPage, mypage" />
 

PageBaseType 属性指明包含页面处理程序的基类的类型和程序集。从 Page 导出的这个类可以自动赋予处理程序扩展的自定义方法和属性集。

 

页面的生命周期

完全识别 HTTP 页面处理程序类后,ASP.NET 运行时将调用处理程序的 ProcessRequest 方法来处理请求。通常情况下,无需更改此方法的实现,因为它是由 Page 类提供的。

 

此实现将从调用为页面构建控件树的 FrameworkInitialize 方法开始。FrameworkInitialize 方法是 TemplateControl 类(Page 本身从此类导出)的一个受保护的虚拟成员。所有为 .aspx 资源动态生成的处理程序都将覆盖 FrameworkInitialize。在此方法中,构建了页面的整个控件树。

 

接下来,ProcessRequest 使页面经历了各个阶段:初始化、加载视图状态信息和回发数据、加载页面的用户代码以及执行回发服务器端事件。之后,页面进入显示模式:收集更新的视图状态,生成 HTML 代码并随后将代码发送到输出控制台。最后,卸载页面,并认为请求处理完毕。

 

在各个阶段中,页面会触发少数几个事件,这些事件可以由 Web 控件和用户定义的代码截取并进行处理。其中的一些事件是嵌入式控件专用的,因此无法在 .aspx 代码级进行处理。

 

要处理特定事件的页面应该明确注册一个适合的处理程序。不过,为了向后兼容早期的 Visual Basic 编程风格,ASP.NET 也支持隐式事件挂钩的形式。默认情况下,页面会尝试将特定的方法名称与事件相匹配,如果实现匹配,则认为此方法就是匹配事件的处理程序。ASP.NET 提供了六种方法名称的特定识别,它们是 Page_InitPage_LoadPage_DataBindPage_PreRenderPage_Unload。这些方法被认为是由 Page 类提供的相应事件的处理程序。HTTP 运行时会自动将这些方法绑定到页面事件,这样,开发人员就不必再编写所需的粘接代码了。例如,如果命名为 Page_Load 的方法绑定到页面的 Load 事件,则可省去以下代码。

 

this.Load += new EventHandler(this.Page_Load);
这种自动识别是被 @Page 预指令的AutoEventWireup 属性控制的。如果这个属性被置false ,
 
技术分享 

实例化(Instantiate):控件在页面或其它控件通过调用其构造函数所实例化时。只有当一个控件在加入控件树中后,该步骤后的所有阶段才会发生。

 

初始化(Initialize):在此阶段中,控件树中的页面与全部控件通过默认的方式调用OnInit方法来触发Init事件,并完成初始化工作。在整个生命周期之前,页面首先建立初始的控件树;在初始阶段之前,为控件赋值。可以实现Page_Init方法来对页面的初始化进行影响,也可以重载控件的OnInit方法来为控件提供初始化逻辑。在这个阶段,控件可以访问其包含的子控件,但却不能访问其父控件或更高层次的控件。

 

开始跟踪视图状态(Begin Tracking View State):这个阶段发生在初始化阶段的末属阶段。在该阶段中,页面自动调用控件的TrackViewState方法,从而启用视图跟踪。当控件提供复杂的属性时,可以重载该方法。

 

加载视图状态(仅用于回传过程)(Load View state):这个过程发生在回传时,而不是初始请求过程中。在此阶段中,控件会将其状态恢复到上一次请求处理完成之后的状态,同时,页面框架自动恢复ViewState字典。

 

加载回传数据(仅用于回传过程,为可选项)(Load Postback Data):只在控件通过实现IPostBackDataHandler接口参与了回传数据处理时,这个阶段才发生在回传中。在这个阶段中,控件通过从已发送的表单数据中利用IPostBackDataHandler接口的LoadPostData方法更新其状态。

 

加载(Load):直至该阶段开始,页面中所有控件都已被初始化,回恢复到它们先前周期的最后状态。]

 

引发修改事件(仅用于回传过程,可选项):只有在控件通过实现IPostBackDataHandler接口参与回传数据处理时,此阶段才会发和在回传中。在些阶段中,控件通过引发事件作为一种信号,即控件状态由于回传而修改。为了参与此阶段,控件必须实现IPostBackDataHandler接口的RaisePostDataChangedEvent方法。

 

引发回传事件(仅用于回传过程,可选项):只有在控件通过实现IPostBackEventHandler接口参与回传事件处理时,此阶段才会发生在回传中。在此阶段,可以通过[实现IPostBackEventHandler接口的RaisePostBackEvent方法来实现逻辑,以便把客房事件映射到服务器端事件。

 

预生成(PreRender):在此阶段中,应该通过重载OnPreRender方法,执行在生成控件之前所需要的任何工作。

 

保存视图状态(Save View State):在此阶段,页面框架自动保存ViewState字典,如果控件需要自定义状态管理,必须通过重载SaveViewState方法来实现自定义状态恢复。这种方法只被EEnableViewState属性为真的控件所调用。

 

生成(Render)

卸载(Unload)

释放(Dispose)

============================================================================

 

常规页生命周期阶段


一般来说,页要经历下表概述的各个阶段。除了页生命周期阶段以外,在请求前后还存在应用程序阶段,但是这些阶段并不特定于页。有关更多信息,请参见 ASP.NET 应用程序生命周期概述。

 

1、页请求
页请求发生在页生命周期开始之前。用户请求页时,ASP.NET 将确定是否需要分析和编译页(从而开始页的生命周期),或者是否可以在不运行页的情况下发送页的缓存版本以进行响应。
2、开始
在开始阶段,将设置页属性,如 Request 和 Response。在此阶段,页还将确定请求是回发请求还是新请求,并设置 IsPostBack 属性。此外,在开始阶段期间,还将设置页的 UICulture 属性。
3、页初始化
页初始化期间,可以使用页中的控件,并将设置每个控件的 UniqueID 属性。此外,任何主题都将应用于页。如果当前请求是回发请求,则回发数据尚未加载,并且控件属性值尚未还原为视图状态中的值。
4、加载
加载期间,如果当前请求是回发请求,则将使用从视图状态和控件状态恢复的信息加载控件属性。
5、验证
在验证期间,将调用所有验证程序控件的 Validate 方法,此方法将设置各个验证程序控件和页的 IsValid 属性。
6、回发事件处理
如果请求是回发请求,则将调用所有事件处理程序。
7、呈现
在呈现之前,会针对该页和所有控件保存视图状态。在呈现阶段中,页会针对每个控件调用 Render 方法,它会提供一个文本编写器,用于将控件的输出写入页的 Response 属性的 OutputStream 中。
8、卸载
完全呈现页并已将页发送至客户端、准备丢弃该页后,将调用卸载。此时,将卸载页属性(如 Response 和 Request)并执行清理。

 

生命周期事件


在页生命周期的每个阶段中,页将引发可运行您自己的代码进行处理的事件。对于控件事件,通过以声明方式使用属性(如 onclick)或以使用代码的方式,均可将事件处理程序绑定到事件。

 

页还支持自动事件连接,即,ASP.NET 将查找具有特定名称的方法,并在引发了特定事件时自动运行这些方法。如果 @ Page 指令的 AutoEventWireup 属性设置为 true(或者未定义该属性,因为该属性默认为 true),页事件将自动绑定至使用 Page_事件的命名约定的方法(如 Page_Load 和 Page_Init)。有关自动事件连接的更多信息,请参见 ASP.NET Web 服务器控件事件模型。

下表列出了最常用的页生命周期事件。除了列出的事件外还有其他事件;不过,大多数页处理方案不使用这些事件。而是主要由 ASP.NET 网页上的服务器控件使用,以初始化和呈现它们本身。如果要编写自己的 ASP.NET 服务器控件,则需要详细了解这些阶段。有关创建自定义控件的信息,请参见 开发自定义 ASP.NET 服务器控件。

01、PreInit
使用该事件来执行下列操作:

检查 IsPostBack 属性来确定是不是第一次处理该页。

创建或重新创建动态控件。

动态设置主控页。

动态设置 Theme 属性。

读取或设置配置文件属性值。

注意 
如果请求是回发请求,则控件的值尚未从视图状态还原。如果在此阶段设置控件属性,则其值可能会在下一事件中被重写。
02、Init
在所有控件都已初始化且已应用所有外观设置后引发。使用该事件来读取或初始化控件属性。
03、InitComplete
由 Page 对象引发。使用该事件来处理要求先完成所有初始化工作的任务。
04、PreLoad
如果需要在 Load 事件之前对页或控件执行处理,请使用该事件。

在 Page 引发该事件后,它会为自身和所有控件加载视图状态,然后会处理 Request 实例包括的任何回发数据。
05、Load
Page 在 Page 上调用 onl oad 事件方法,然后以递归方式对每个子控件执行相同操作,如此循环往复,直到加载完本页和所有控件为止。

使用 onl oad 事件方法来设置控件中的属性并建立数据库连接。
06、控件事件
使用这些事件来处理特定控件事件,如 Button 控件的 Click 事件或 TextBox 控件的 TextChanged 事件。

注意 
在回发请求中,如果页包含验证程序控件,请在执行任何处理之前检查 Page 和各个验证控件的 IsValid 属性。
07、LoadComplete
对需要加载页上的所有其他控件的任务使用该事件。
08、PreRender
在该事件发生前:

Page 对象会针对每个控件和页调用 EnsureChildControls。

设置了 DataSourceID 属性的每个数据绑定控件会调用 DataBind 方法。有关更多信息,请参见下面的数据绑定控件的数据绑定事件。

页上的每个控件都会发生 PreRender 事件。使用该事件对页或其控件的内容进行最后更改。
09、SaveStateComplete
在该事件发生前,已针对页和所有控件保存了 ViewState。将忽略此时对页或控件进行的任何更改。

使用该事件执行满足以下条件的任务:要求已经保存了视图状态,但未对控件进行任何更改。
10、Render
这不是事件;在处理的这个阶段,Page 对象会在每个控件上调用此方法。所有 ASP.NET Web 服务器控件都有一个用于写出发送给浏览器的控件标记的 Render 方法。

如果创建自定义控件,通常要重写此方法以输出控件的标记。不过,如果自定义控件只合并标准的 ASP.NET Web 服务器控件,不合并自定义标记,则不需要重写 Render 方法。有关更多信息,请参见 开发自定义 ASP.NET 服务器控件。

用户控件(.ascx 文件)自动合并呈现,因此不需要在代码中显式呈现该控件。
11、Unload
该事件首先针对每个控件发生,继而针对该页发生。在控件中,使用该事件对特定控件执行最后清理,如关闭控件特定数据库连接。

对于页自身,使用该事件来执行最后清理工作,如:关闭打开的文件和数据库连接,或完成日志记录或其他请求特定任务。

注意 
在卸载阶段,页及其控件已被呈现,因此无法对响应流做进一步更改。如果尝试调用方法(如 Response.Write 方法),则该页将引发异常。

=============================================================================

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class _Default : Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
    }
    #region OnPreInit 第一步
    protected override void OnPreInit(EventArgs e)
    {
        //检查 IsPostBack 属性来确定是不是第一次处理该页。
        //创建或重新创建动态控件。
        //动态设置主控页。
        //动态设置 Theme 属性。
        //读取或设置配置文件属性值。
        //注意  
        //如果请求是回发请求,则控件的值尚未从视图状态还原。如果在此阶段设置控件属性,则其值可能会在下一事件中被重写。
 
        base.OnPreInit(e);
    }
    #endregion
    #region OnInit 第二步
    protected override void OnInit(EventArgs e)
    {
        //在所有控件都已初始化且已应用所有外观设置后引发。使用该事件来读取或初始化控件属性。
        base.OnInit(e);
    }
    #endregion
    #region OnInitComplete 第三步
    protected override void OnInitComplete(EventArgs e)
    {
        //由 Page 对象引发。使用该事件来处理要求先完成所有初始化工作的任务。
        base.OnInitComplete(e);
    }
    #endregion
    #region PreLoad 第四步
    protected override void OnPreLoad(EventArgs e)
    {
        //如果需要在 Load 事件之前对页或控件执行处理,请使用该事件。 
        //在 Page 引发该事件后,它会为自身和所有控件加载视图状态,然后会处理 Request 实例包括的任何回发数据。
        base.OnPreLoad(e);
    }
    #endregion 
    #region onl oad 第五步
    protected override void onl oad(EventArgs e)
    {
        //Page 在 Page 上调用 onl oad 事件方法,然后以递归方式对每个子控件执行相同操作,如此循环往复,直到加载完本页和所有控件为止。
        //使用 onl oad 事件方法来设置控件中的属性并建立数据库连接。
        base.OnLoad(e);
    }
    #endregion
    #region 控件事件 第六步
    protected void Button1_Click(object sender, EventArgs e)
    {
        //用这些事件来处理特定控件事件,如 Button 控件的 Click 事件或 TextBox 控件的 TextChanged 事件。
        //注意  
        //在回发请求中,如果页包含验证程序控件,请在执行任何处理之前检查 Page 和各个验证控件的 IsValid 属性。
 
    }
    #endregion
    #region onl oadComplete 第七步
    protected override void onl oadComplete(EventArgs e)
    {
        //对需要加载页上的所有其他控件的任务使用该事件。
        base.OnLoadComplete(e);
    }
    #endregion
    #region OnPreRender 第八步
    protected override void OnPreRender(EventArgs e)
    {
        //在该事件发生前:
        //Page 对象会针对每个控件和页调用 EnsureChildControls。 
        //设置了 DataSourceID 属性的每个数据绑定控件会调用 DataBind 方法。有关更多信息,请参见下面的数据绑定控件的数据绑定事件。
        //页上的每个控件都会发生 PreRender 事件。使用该事件对页或其控件的内容进行最后更改。
        base.OnPreRender(e);
    }
    #endregion 
    #region SaveStateComplete 第九步
    protected override void OnSaveStateComplete(EventArgs e)
    {
        //在该事件发生前,已针对页和所有控件保存了 ViewState。将忽略此时对页或控件进行的任何更改。
        //使用该事件执行满足以下条件的任务:要求已经保存了视图状态,但未对控件进行任何更改。
        base.OnSaveStateComplete(e);
    }
    #endregion
    #region Render 第十步
    //Render
    //这不是事件;在处理的这个阶段,Page 对象会在每个控件上调用此方法。所有 ASP.NET Web 服务器控件都有一个用于写出发送给浏览器的控件标记的 Render 方法。
    //如果创建自定义控件,通常要重写此方法以输出控件的标记。不过,如果自定义控件只合并标准的 ASP.NET Web 服务器控件,不合并自定义标记,则不需要重写 Render 方法。有关更多信息,请参见开发自定义 ASP.NET 服务器控件。
    //用户控件(.ascx 文件)自动合并呈现,因此不需要在代码中显式呈现该控件。
    #endregion
    #region OnUnload 第十一步       
    protected override void OnUnload(EventArgs e)
    {
        //该事件首先针对每个控件发生,继而针对该页发生。在控件中,使用该事件对特定控件执行最后清理,如关闭控件特定数据库连接。
        //对于页自身,使用该事件来执行最后清理工作,如:关闭打开的文件和数据库连接,或完成日志记录或其他请求特定任务。
        //注意  
        //在卸载阶段,页及其控件已被呈现,因此无法对响应流做进一步更改。如果尝试调用方法(如 Response.Write 方法),则该页将引发异常。
 
        base.OnUnload(e);
    }
    #endregion
}

 

引用键接:http://www.cnblogs.com/oletan/archive/2008/11/04/1326587.html

            http://www.cnblogs.com/chinamvc/archive/2009/08/16/1547000.html

【IHttpHandler】ASP.NET 生命周期