zoukankan      html  css  js  c++  java
  • asp.net 页面生命周期

    对于Asp.net页面层开发无论是写页面还是写控件,我觉得都可以用一句话描述:"Do the right thing at the right time in the right place."这是07年底的一篇东西,还是有点价值整理出来与大家共享。 

        本文从两个粒度对Asp.net生命周期做了展示,一是通过记录页面事件的触发顺序看请求的处理流程,一是通过Reflector看Page类内部对请求处理的实现,为了清晰我清理掉了ETW相关的代码保留了一个简化却足可以说明问题的流程骨架;

        本文覆盖以下内容:

    1. 页面事件的触发顺序展示
    2. 清理掉ETW代码后的,Page类内部对请求处理的实现
    3. MSDN关于Asp.net生命周期非常重要的四个表格
    4. 演示源代码下载


     

     1using System;
     2using System.Configuration;
     3using System.Data;
     4using System.Web;
     5using System.Web.Security;
     6using System.Web.UI;
     7using System.Web.UI.HtmlControls;
     8using System.Web.UI.WebControls;
     9using System.Web.UI.WebControls.WebParts;
    10
    11public partial class _Default : System.Web.UI.Page
    12{
    13    protected void Page_PreInit(object sender, EventArgs e)
    14    {
    15        Response.Write("Page_PreInit<br/>");
    16    }
    17    protected void Page_Init(object sender, EventArgs e)
    18    {
    19        Response.Write("Page_Init<br/>");
    20
    21    }
    22    protected void Page_InitComplete(object sender, EventArgs e)
    23    {
    24        Response.Write("Page_InitComplete<br/>");
    25
    26    }
    27    protected void Page_PreLoad(object sender, EventArgs e)
    28    {
    29        Response.Write("Page_PreLoad<br/>");
    30
    31    }
    32    protected void Page_Load(object sender, EventArgs e)
    33    {
    34        Response.Write("Page_Load<br/>");
    35
    36    }
    37    protected void Page_LoadComplete(object sender, EventArgs e)
    38    {
    39        Response.Write("Page_LoadComplete<br/>");
    40
    41    }
    42    protected void Page_PreRender(object sender, EventArgs e)
    43    {
    44        Response.Write("Page_PreRender<br/>");
    45
    46    }
    47    protected void Page_SaveStateComplete(object sender, EventArgs e)
    48    {
    49        Response.Write("Page_SaveStateComplete<br/>");
    50
    51    }
    52
    53   
    54    protected void Page_Unload(object sender, EventArgs e)
    55    {
    56        int i = 0;
    57        i++;//这行代码是用来设置断点的,为什么不用Response.Write?你说呢?
    58
    59    }
    60
    61
    62    protected void Button1_Click(object sender, EventArgs e)
    63    {
    64        Label1.Text = "ControlEvent";
    65        Response.Write("Button事件触发!<br/>");
    66    }
    67}
    68
    69
    70


    运行结果:
     

    Page_PreInit

    Page_Init

    Page_InitComplete

    Page_PreLoad

    Page_Load

    Page_LoadComplete

    Page_PreRender

    Page_SaveStateComplete


    点击页面的Button后的输出:

    Page_PreInit

    Page_Init

    Page_InitComplete

    Page_PreLoad

    Page_Load

    Button事件触发!

    Page_LoadComplete

    Page_PreRender

    Page_SaveStateComplete

    我们从一个更细的粒度,在Reflector中看Page对请求处理的代码:

      1 private void ProcessRequestMain(bool includeStagesBeforeAsyncPoint, bool includeStagesAfterAsyncPoint)
      2 {
      3     try
      4     {
      5         HttpContext context = this.Context;
      6         string str = null;
      7         if (includeStagesBeforeAsyncPoint)
      8         {
      9             if (this.IsInAspCompatMode)
     10             {
     11                 AspCompatApplicationStep.OnPageStartSessionObjects();
     12             }
     13             if (this.PageAdapter != null)
     14             {
     15                 this._requestValueCollection = this.PageAdapter.DeterminePostBackMode();
     16             }
     17             else
     18             {
     19                 this._requestValueCollection = this.DeterminePostBackMode();
     20             }
     21             string callbackControlID = string.Empty;
     22             if (this.DetermineIsExportingWebPart())
     23             {
     24                 if (!RuntimeConfig.GetAppConfig().WebParts.EnableExport)
     25                 {
     26                     throw new InvalidOperationException(SR.GetString("WebPartExportHandler_DisabledExportHandler"));
     27                 }
     28                 str = this.Request.QueryString["webPart"];
     29                 if (string.IsNullOrEmpty(str))
     30                 {
     31                     throw new InvalidOperationException(SR.GetString("WebPartExportHandler_InvalidArgument"));
     32                 }
     33                 if (string.Equals(this.Request.QueryString["scope"], "shared", StringComparison.OrdinalIgnoreCase))
     34                 {
     35                     this._pageFlags.Set(4);
     36                 }
     37                 string str3 = this.Request.QueryString["query"];
     38                 if (str3 == null)
     39                 {
     40                     str3 = string.Empty;
     41                 }
     42                 this.Request.QueryStringText = str3;
     43                 context.Trace.IsEnabled = false;
     44             }
     45             if (this._requestValueCollection != null)
     46             {
     47                 if (this._requestValueCollection["__VIEWSTATEENCRYPTED"] != null)
     48                 {
     49                     this.ContainsEncryptedViewState = true;
     50                 }
     51                 callbackControlID = this._requestValueCollection["__CALLBACKID"];
     52                 if ((callbackControlID != null) && (this._request.HttpVerb == HttpVerb.POST))
     53                 {
     54                     this._isCallback = true;
     55                 }
     56                 else if (!this.IsCrossPagePostBack)
     57                 {
     58                     VirtualPath path = null;
     59                     if (this._requestValueCollection["__PREVIOUSPAGE"] != null)
     60                     {
     61                         try
     62                         {
     63                             path = VirtualPath.CreateNonRelativeAllowNull(DecryptString(this.        _requestValueCollection["__PREVIOUSPAGE"]));
     64                         }
     65                         catch (CryptographicException)
     66                         {
     67                             this._pageFlags[8] = true;
     68                         }
     69                         if ((path != null) && (path != this.Request.CurrentExecutionFilePathObject))
     70                         {
     71                             this._pageFlags[8] = true;
     72                             this._previousPagePath = path;
     73                         }
     74                     }
     75                 }
     76             }
     77             if (this.MaintainScrollPositionOnPostBack)
     78             {
     79                 this.LoadScrollPosition();
     80             }
     81             
     82             this.PerformPreInit();          
     83             
     84             this.InitRecursive(null);
     85             
     86             this.OnInitComplete(EventArgs.Empty);
     87             
     88             if (this.IsPostBack)
     89             {
     90                 this.LoadAllState();
     91             
     92                 this.ProcessPostData(this._requestValueCollection, true);
     93             
     94             }
     95             
     96             
     97             this.OnPreLoad(EventArgs.Empty);
     98             
     99             this.LoadRecursive();
    100             
    101             if (this.IsPostBack)
    102             {
    103                 this.ProcessPostData(this._leftoverPostData, false);
    104             
    105                 this.RaiseChangedEvents();
    106              
    107                 this.RaisePostBackEvent(this._requestValueCollection);
    108              
    109             }
    110             
    111             this.OnLoadComplete(EventArgs.Empty);
    112             
    113             if (this.IsPostBack && this.IsCallback)
    114             {
    115                 this.PrepareCallback(callbackControlID);
    116             }
    117             else if (!this.IsCrossPagePostBack)
    118             {
    119             
    120                 this.PreRenderRecursiveInternal();
    121              }
    122         }
    123         if ((this._asyncInfo == null) || this._asyncInfo.CallerIsBlocking)
    124         {
    125             this.ExecuteRegisteredAsyncTasks();
    126         }
    127         if (includeStagesAfterAsyncPoint)
    128         {
    129             if (this.IsCallback)
    130             {
    131                 this.RenderCallback();
    132             }
    133             else if (!this.IsCrossPagePostBack)
    134             {
    135                 this.PerformPreRenderComplete();
    136             
    137                 if (context.TraceIsEnabled)
    138                 {
    139                     this.BuildPageProfileTree(this.EnableViewState);
    140                     this.Trace.Write("aspx.page", "Begin SaveState");
    141                 }
    142             
    143                 this.SaveAllState();
    144             
    145                 this.OnSaveStateComplete(EventArgs.Empty);
    146                 if (str != null)
    147                 {
    148                     this.ExportWebPart(str);
    149                 }
    150                 else
    151                 {
    152                     this.RenderControl(this.CreateHtmlTextWriter(this.Response.Output));
    153                 }
    154             
    155                 this.CheckRemainingAsyncTasks(false);
    156             }
    157         }
    158     }
    159     catch (ThreadAbortException exception)
    160     {
    161         HttpApplication.CancelModuleException exceptionState = exception.ExceptionState as HttpApplication.CancelModuleException;
    162         if (((!includeStagesBeforeAsyncPoint || !includeStagesAfterAsyncPoint) || ((this._context.Handler != this) || (this._context.ApplicationInstance == null))) || ((exceptionState == null) || exceptionState.Timeout))
    163         {
    164             this.CheckRemainingAsyncTasks(true);
    165             throw;
    166         }
    167         this._context.ApplicationInstance.CompleteRequest();
    168         Thread.ResetAbort();
    169     }
    170     catch (ConfigurationException)
    171     {
    172         throw;
    173     }
    174     catch (Exception exception3)
    175     {
    176         PerfCounters.IncrementCounter(AppPerfCounter.ERRORS_DURING_REQUEST);
    177         PerfCounters.IncrementCounter(AppPerfCounter.ERRORS_TOTAL);
    178         if (!this.HandleError(exception3))
    179         {
    180             throw;
    181         }
    182     }
    183 }
    184 
    185  
    186 
    187  
    188 
    private void PerformPreInit()
    {
               this.OnPreInit(EventArgs.Empty);
        this.InitializeThemes();//看到主题和模板页是什么时候加载了吧
        this.ApplyMasterPage();
        this._preInitWorkComplete = true;
    }


    MSDN上对Asp.net生命周期解释有非常重要的四个表格:

    Stage

    Description

    Page request

    The page request occurs before the page life cycle begins. When the page is requested by a user, ASP.NET determines whether the page needs to be parsed and compiled (therefore beginning the life of a page), or whether a cached version of the page can be sent in response without running the page.

    Start

    In the start step, page properties such as Request and Response are set. At this stage, the page also determines whether the request is a postback or a new request and sets the IsPostBack property. Additionally, during the start step, the page's UICulture property is set.

    Page initialization

    During page initialization, controls on the page are available and each control's UniqueID property is set. Any themes are also applied to the page. If the current request is a postback, the postback data has not yet been loaded and control property values have not been restored to the values from view state.

    Load

    During load, if the current request is a postback, control properties are loaded with information recovered from view state and control state.

    Validation

    During validation, the Validate method of all validator controls is called, which sets the IsValid property of individual validator controls and of the page.

    Postback event handling

    If the request is a postback, any event handlers are called.

    Rendering

    Before rendering, view state is saved for the page and all controls. During the rendering phase, the page calls the Render method for each control, providing a text writer that writes its output to the OutputStream of the page's Response property.

    Unload

    Unload is called after the page has been fully rendered, sent to the client, and is ready to be discarded. At this point, page properties such as Response and Request are unloaded and any cleanup is performed.

    Life-cycle Events

    Page Event

    Typical Use

    PreInit

    Use this event for the following:

    1. Check the IsPostBack property to determine whether this is the first time the page is being processed.
    2. Create or re-create dynamic controls.
    3. Set a master page dynamically.
    4. Set the Theme property dynamically.
    5. Read or set profile property values.
      Note:
      If the request is a postback, the values of the controls have not yet been restored from view state. If you set a control property at this stage, its value might be overwritten in the next event.

    Init

    Raised after all controls have been initialized and any skin settings have been applied. Use this event to read or initialize control properties.

    InitComplete

    Raised by the Page object. Use this event for processing tasks that require all initialization be complete.

    PreLoad

    Use this event if you need to perform processing on your page or control before the Load event.

    After the Page raises this event, it loads view state for itself and all controls, and then processes any postback data included with the Request instance.

    Load

    The Page calls the OnLoad event method on the Page, then recursively does the same for each child control, which does the same for each of its child controls until the page and all controls are loaded.

    Use the OnLoad event method to set properties in controls and establish database connections.

    Control events

    Use these events to handle specific control events, such as a Button control's Click event or a TextBox control's TextChanged event.

    Note:

    In a postback request, if the page contains validator controls, check the IsValid property of the Page and of individual validation controls before performing any processing.

    LoadComplete

    Use this event for tasks that require that all other controls on the page be loaded.

    PreRender

    Before this event occurs:

    1. The Page object calls EnsureChildControls for each control and for the page.
    2. Each data bound control whose DataSourceID property is set calls its DataBind method. For more information, see Data Binding Events for Data-Bound Controlslater in this topic.

      The PreRender event occurs for each control on the page. Use the event to make final changes to the contents of the page or its controls.

    SaveStateComplete

    Before this event occurs, ViewState has been saved for the page and for all controls. Any changes to the page or controls at this point will be ignored.

    Use this event perform tasks that require view state to be saved, but that do not make any changes to controls.

    Render

    This is not an event; instead, at this stage of processing, the Page object calls this method on each control. All ASP.NET Web server controls have a Render method that writes out the control's markup that is sent to the browser.

    If you create a custom control, you typically override this method to output the control's markup. However, if your custom control incorporates only standard ASP.NET Web server controls and no custom markup, you do not need to override the Render method. For more information, see Developing Custom ASP.NET Server Controls.

    A user control (an .ascx file) automatically incorporates rendering, so you do not need to explicitly render the control in code.

    Unload

    This event occurs for each control and then for the page. In controls, use this event to do final cleanup for specific controls, such as closing control-specific database connections.

    For the page itself, use this event to do final cleanup work, such as closing open files and database connections, or finishing up logging or other request-specific tasks.

    Note:

    During the unload stage, the page and its controls have been rendered, so you cannot make further changes to the response stream. If you attempt to call a method such as the Response.Write method, the page will throw an exception.

    Data Binding Events for Data-Bound Controls

    To help you understand the relationship between the page life cycle and data binding events, the following table lists data-related events in data-bound controls such as the GridView, DetailsView, and FormView controls.

    Control Event

    Typical Use

    DataBinding

    This event is raised by data-bound controls before the PreRender event of the containing control (or of the Page object) and marks the beginning of binding the control to the data.

    Use this event to manually open database connections, if required. (The data source controls often make this unnecessary.)

    RowCreated (GridView only) or ItemCreated (DataList, DetailsView, SiteMapPath, DataGrid, FormView, Repeater, and ListView controls)

    Use this event to manipulate content that is not dependent on data binding. For example, at run time, you might programmatically add formatting to a header or footer row in a GridView control.

    RowDataBound (GridView only) or ItemDataBound (DataList, SiteMapPath, DataGrid, Repeater, and ListView controls)

    When this event occurs, data is available in the row or item, so you can format data or set the FilterExpression property on child data source controls for displaying related data within the row or item.

    DataBound

    This event marks the end of data-binding operations in a data-bound control. In a GridView control, data binding is complete for all rows and any child controls.

    Use this event to format data bound content or to initiate data binding in other controls that depend on values from the current control's content. (For details, see "Catch-up Events for Added Controls" earlier in this topic.)

    Login Control Events

    The Login control can use settings in the Web.config file to manage membership authentication automatically. However, if your application requires you to customize how the control works, or if you want to understand how Login control events relate to the page life cycle, you can use the events listed in the following table.

    Control Event

    Typical Use

    LoggingIn

    This event is raised during a postback, after the page's LoadComplete event has occurred. It marks the beginning of the login process.

    Use this event for tasks that must occur prior to beginning the authentication process.

    Authenticate

    This event is raised after the LoggingIn event.

    Use this event to override or enhance the default authentication behavior of a Login control.

    LoggedIn

    This event is raised after the user name and password have been authenticated.

    Use this event to redirect to another page or to dynamically set the text in the control. This event does not occur if there is an error or if authentication fails.

    LoginError

    This event is raised if authentication was not successful.

    Use this event to set text in the control that explains the problem or to direct the user to a different page.


    演示代码下载地址:https://files.cnblogs.com/me-sa/HttpStudy.rar

    评论:

     

    评论
    好文
    很好的讲解了页面的生命周期,呵呵,不错,如果把后面的表格用自己的话更加清楚的讲一下,而不是照搬MS的,就更好了。
    求你做好事做到底吧,翻译一下下面的,谢谢!
    webform的生命周期太复杂了,这也是我转向ASP.NET MVC的重要原因,还是回归单纯的form post比较好,复杂的用ajax就行了。
    有一张asp.net webform生命周期的图,如果把那张贴出来效果可能更好点
    建议整理下版面,代码162行这
    if (((!includeStagesBeforeAsyncPoint || !includeStagesAfterAsyncPoint) || ((this._context.Handler != this) || (this._context.ApplicationInstance == null))) || ((exceptionState == null) || exceptionState.Timeout))
    换行显示下就不会出现横向滚动条啦.
    #7楼[楼主]
     

    ASP.NET 页生命周期概述

     

    ASP.NET 页运行时,此页将经历一个生命周期,在生命周期中将执行一系列处理步骤。这些步骤包括初始化、实例化控件、还原和维护状态、运行事件处理程序代码以及进行呈现。了解页生命周期非常重要,因为这样做您就能在生命周期的合适阶段编写代码,以达到预期效果。此外,如果您要开发自定义控件,就必须熟悉页生命周期,以便正确进行控件初始化,使用视图状态数据填充控件属性以及运行任何控件行为代码。(控件的生命周期基于页的生命周期,但是页引发的控件事件比单独的 ASP.NET 页中可用的事件多。)

    常规页生命周期阶段

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

    阶段

    说明

    页请求

    页请求发生在页生命周期开始之前。用户请求页时,ASP.NET 将确定是否需要分析和编译页(从而开始页的生命周期),或者是否可以在不运行页的情况下发送页的缓存版本以进行响应。

    开始

    在开始阶段,将设置页属性,如 RequestResponse。在此阶段,页还将确定请求是回发请求还是新请求,并设置 IsPostBack 属性。此外,在开始阶段期间,还将设置页的 UICulture 属性。

    页初始化

    页初始化期间,可以使用页中的控件,并将设置每个控件的 UniqueID 属性。此外,任何主题都将应用于页。如果当前请求是回发请求,则回发数据尚未加载,并且控件属性值尚未还原为视图状态中的值。

    加载

    加载期间,如果当前请求是回发请求,则将使用从视图状态和控件状态恢复的信息加载控件属性。

    验证

    在验证期间,将调用所有验证程序控件的 Validate 方法,此方法将设置各个验证程序控件和页的 IsValid 属性。

    回发事件处理

    如果请求是回发请求,则将调用所有事件处理程序。

    呈现

    在呈现之前,会针对该页和所有控件保存视图状态。在呈现阶段中,页会针对每个控件调用 Render 方法,它会提供一个文本编写器,用于将控件的输出写入页的 Response 属性的 OutputStream 中。

    卸载

    完全呈现页并已将页发送至客户端、准备丢弃该页后,将调用卸载。此时,将卸载页属性(如 ResponseRequest)并执行清理。

    生命周期事件

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

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

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

    页事件

    典型使用

    PreInit

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

    1. 检查 IsPostBack 属性来确定是不是第一次处理该页。
    2. 创建或重新创建动态控件。
    3. 动态设置主控页。
    4. 动态设置 Theme 属性。
    5. 读取或设置配置文件属性值。
      注意
      如果请求是回发请求,则控件的值尚未从视图状态还原。如果在此阶段设置控件属性,则其值可能会在下一事件中被重写。

    Init

    在所有控件都已初始化且已应用所有外观设置后引发。使用该事件来读取或初始化控件属性。

    InitComplete

    Page 对象引发。使用该事件来处理要求先完成所有初始化工作的任务。

    PreLoad

    如果需要在 Load 事件之前对页或控件执行处理,请使用该事件。

    Page 引发该事件后,它会为自身和所有控件加载视图状态,然后会处理 Request 实例包括的任何回发数据。

    Load

    PagePage 上调用 OnLoad 事件方法,然后以递归方式对每个子控件执行相同操作,如此循环往复,直到加载完本页和所有控件为止。

    使用 OnLoad 事件方法来设置控件中的属性并建立数据库连接。

    控件事件

    使用这些事件来处理特定控件事件,如 Button 控件的 Click 事件或 TextBox 控件的 TextChanged 事件。

    注意

    在回发请求中,如果页包含验证程序控件,请在执行任何处理之前检查 Page 和各个验证控件的 IsValid 属性。

    LoadComplete

    对需要加载页上的所有其他控件的任务使用该事件。

    PreRender

    在该事件发生前:

    1. Page 对象会针对每个控件和页调用 EnsureChildControls
    2. 设置了 DataSourceID 属性的每个数据绑定控件会调用 DataBind 方法。有关更多信息,请参见下面的数据绑定控件的数据绑定事件

      页上的每个控件都会发生 PreRender 事件。使用该事件对页或其控件的内容进行最后更改。

    SaveStateComplete

    在该事件发生前,已针对页和所有控件保存了 ViewState。将忽略此时对页或控件进行的任何更改。

    使用该事件执行满足以下条件的任务:要求已经保存了视图状态,但未对控件进行任何更改。

    Render

    这不是事件;在处理的这个阶段,Page 对象会在每个控件上调用此方法。所有 ASP.NET Web 服务器控件都有一个用于写出发送给浏览器的控件标记的 Render 方法。

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

    用户控件(.ascx 文件)自动合并呈现,因此不需要在代码中显式呈现该控件。

    Unload

    该事件首先针对每个控件发生,继而针对该页发生。在控件中,使用该事件对特定控件执行最后清理,如关闭控件特定数据库连接。

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

    注意

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

    其他的页生命周期注意事项

    各个 ASP.NET 服务器控件都有自己的生命周期,该生命周期与页生命周期类似。例如,控件的 InitLoad 事件在相应的页事件期间发生。

    虽然 InitLoad 都在每个控件上以递归方式发生,但它们的发生顺序相反。每个子控件的 Init 事件(还有 Unload 事件)在为其容器引发相应的事件之前发生(由下到上)。但是,容器的 Load 事件是在其子控件的 Load 事件之前发生(由上到下)。

    可以通过处理控件的事件(如 Button 控件的 Click 事件和 ListBox 控件的 SelectedIndexChanged 事件)来自定义控件的外观或内容。在某些情况下,可能也需处理控件的 DataBindingDataBound 事件。有关更多信息,请参见各个控件的类参考主题以及开发自定义 ASP.NET 服务器控件

    当从 Page 类继承类时,除了可以处理由页引发的事件以外,还可以重写页的基类中的方法。例如,可以重写页的 InitializeCulture 方法,以便动态设置区域性信息。注意,在使用 Page_事件语法创建事件处理程序时,将隐式调用基实现,因此无需在方法中调用它。例如,无论是否创建 Page_Load 方法,始终都会调用页基类的 OnLoad 方法。但是,如果使用 override 关键字(在 Visual Basic 中为 Overrides)重写页的 OnLoad 方法,则必须显式调用基方法。例如,如果在页中重写 OnLoad 方法,则必须调用 base.Load(在 Visual Basic 中为 MyBase.Load)以运行基实现。

    添加的控件的追赶事件

    如果控件是在运行时动态创建的,或者是以声明方式在数据绑定控件的模板中创建的,它们的事件最初与页上的其他控件的事件并不同步。例如,对于运行时添加的控件,InitLoad 事件在页生命周期中的发生时间可能要比以声明方式创建的控件的相同事件晚得多。因此,从实例化那一刻起,动态添加的控件的事件就一直是在模板中的控件的事件之后发生,直到赶上该控件加入 Controls 集合时所对应事件为止。

    一般来说,除非存在嵌套数据绑定控件,否则,您不必担心这种情况。如果子控件已执行数据绑定,但其容器控件尚未执行数据绑定,则子控件中的数据与其容器控件中的数据可能不同步。如果子控件中的数据根据容器控件中的数据绑定值执行了处理,这种情况则尤其显著。

    例如,假定有一个 GridView,它的每一行显示一条公司记录,此外,有一个 ListBox 控件包含公司管理者列表。若要填充管理者列表,则需要将 ListBox 控件绑定到一个数据源控件(如 SqlDataSource),后者在查询中使用 CompanyID 来检索公司管理者数据。

    如果以声明方式设置了 ListBox 控件的数据绑定属性(如 DataSourceIDDataMember),ListBox 控件将尝试在包含行的 DataBinding 事件期间绑定到其数据源。不过,行的 CompanyID 字段直到 GridView 控件的 RowDataBound 事件发生后才包含值。这种情况下,先绑定子控件(ListBox 控件),后绑定包含控件(GridView 控件),因此它们的数据绑定阶段并不同步。

    若要避免此种情况,需要将 ListBox 控件的数据源控件与 ListBox 控件自身放在同一模板项中,并且不要以声明方式设置 ListBox 的数据绑定属性。而应在 RowDataBound 事件期间在运行时以编程方式设置它们,这样,到 CompanyID 信息可用时 ListBox 控件才会绑定到其数据。

    有关更多信息,请参见使用数据源控件绑定到数据

    数据绑定控件的数据绑定事件

    为了帮助您理解页生命周期与数据绑定事件之间的关系,下表列出了数据绑定控件(如 GridViewDetailsViewFormView 控件)中与数据相关的事件。

    控件事件

    典型使用

    DataBinding

    该事件在包含控件(或 Page 对象)的 PreRender 事件之前由数据绑定控件引发,会标记控件到数据的绑定过程的起点。

    如果需要,使用该事件以手动方式打开数据库连接。(数据源控件通常不需要如此操作。)

    RowCreated(仅限 GridView)或 ItemCreatedDataListDetailsViewSiteMapPathDataGridFormViewRepeater 控件)

    使用该事件来操作不依赖于数据绑定的内容。例如,在运行时,可以以编程方式向 GridView 控件中的页眉或页脚行添加格式。

    RowDataBound(仅限 GridView)或 ItemDataBoundDataListSiteMapPathDataGridRepeater 控件)

    当该事件发生时,行或项中的数据可用,因此,可以在子数据源控件上格式化数据或设置 FilterExpression 属性,以便显示行或项中的相关数据。

    DataBound

    该事件在数据绑定控件中标记数据绑定操作的结尾。在 GridView 控件中,会针对所有行和任何子控件完成数据绑定。

    使用该事件格式化数据绑定内容,或在依赖来自当前控件的内容的值的其他控件中启动数据绑定。(有关详细信息,请参见本主题中前面的“添加的控件的追赶事件”。)

    登录控件事件

    Login 控件可以使用 Web.config 文件中的设置来自动管理成员资格验证。不过,如果应用程序要求您自定义控件的工作方式,或者您要了解 Login 控件事件与页生命周期的关联方式,可以使用下表中列出的事件。

    控件事件

    典型使用

    LoggingIn

    在回发期间,当页的 LoadComplete 事件发生后就会引发该事件。它标记登录过程的起点。

    对必须在验证过程开始前发生的任务使用该事件。

    Authenticate

    该事件在 LoggingIn 事件之后引发。

    使用该事件来重写或增强 Login 控件的默认验证行为。

    LoggedIn

    该事件在验证用户名和密码后引发。

    使用该事件来重定向到另一个页或动态设置控件中的文本。如果出现错误或验证失败,就不会发生该事件。

    LoginError

    如果验证失败,将引发该事件。

    使用该事件来设置控件中的问题解释文本或将用户定向到不同的页。

     

    源文档 <http://msdn2.microsoft.com/zh-cn/library/ms178472(VS.80).aspx>

    #8楼[楼主]
     
    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 处理程序介绍

    ASP.NET 接收对应用程序的第一个请求。

    当 ASP.NET 接收到对应用程序中任何资源的第一个请求时,名为 ApplicationManager 的类会创建一个应用程序域。应用程序域为全局变量提供应用程序隔离,并允许单独卸载每个应用程序。在应用程序域中,将为名为 HostingEnvironment 的类创建一个实例,该实例提供对有关应用程序的信息(如存储该应用程序的文件夹的名称)的访问。

    下面的关系图说明了这种关系:

    如果需要,ASP.NET 还可对应用程序中的顶级项进行编译,其中包括 App_Code 文件夹中的应用程序代码。有关更多信息,请参见本主题后面的“编译生命周期”。

    为每个请求创建 ASP.NET 核心对象。

    创建了应用程序域并对 HostingEnvironment 对象进行了实例化之后,ASP.NET 将创建并初始化核心对象,如 HttpContextHttpRequestHttpResponseHttpContext 类包含特定于当前应用程序请求的对象,如 HttpRequestHttpResponse 对象。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 类的开发人员尤其需要注意这些事件。

    1. 对请求进行验证,将检查浏览器发送的信息,并确定其是否包含潜在恶意标记。有关更多信息,请参见 ValidateRequest脚本侵入概述
    2. 如果已在 Web.config 文件的 UrlMappingsSection 节中配置了任何 URL,则执行 URL 映射。
    3. 引发 BeginRequest 事件。
    4. 引发 AuthenticateRequest 事件。
    5. 引发 PostAuthenticateRequest 事件。
    6. 引发 AuthorizeRequest 事件。
    7. 引发 PostAuthorizeRequest 事件。
    8. 引发 ResolveRequestCache 事件。
    9. 引发 PostResolveRequestCache 事件。
    10. 根据所请求资源的文件扩展名(在应用程序的配置文件中映射),选择实现 IHttpHandler 的类,对请求进行处理。如果该请求针对从 Page 类派生的对象(页),并且需要对该页进行编译,则 ASP.NET 会在创建该页的实例之前对其进行编译。
    11. 引发 PostMapRequestHandler 事件。
    12. 引发 AcquireRequestState 事件。
    13. 引发 PostAcquireRequestState 事件。
    14. 引发 PreRequestHandlerExecute 事件。
    15. 为该请求调用合适的 IHttpHandler 类的 ProcessRequest 方法(或异步版 BeginProcessRequest)。例如,如果该请求针对某页,则当前的页实例将处理该请求。
    16. 引发 PostRequestHandlerExecute 事件。
    17. 引发 ReleaseRequestState 事件。
    18. 引发 PostReleaseRequestState 事件。
    19. 如果定义了 Filter 属性,则执行响应筛选。
    20. 引发 UpdateRequestCache 事件。
    21. 引发 PostUpdateRequestCache 事件。
    22. 引发 EndRequest 事件。

    生命周期事件和 Global.asax 文件

    在应用程序的生命周期期间,应用程序会引发可处理的事件并调用可重写的特定方法。若要处理应用程序事件或方法,可以在应用程序根目录中创建一个名为 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_StartApplication_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.Init

    在创建了所有模块之后,对 HttpApplication 类的每个实例都调用一次。

    Dispose

    在销毁应用程序实例之前调用。可使用此方法手动释放任何非托管资源。有关更多信息,请参见清理非托管资源

    Application_End

    在卸载应用程序之前对每个应用程序生命周期调用一次。

    编译生命周期

    在第一次对应用程序发出请求时,ASP.NET 按特定顺序编译应用程序项。要编译的第一批项称为顶级项。在第一次请求之后,仅当依赖项更改时才会重新编译顶级项。下表描述编译 ASP.NET 顶级项的顺序。

    说明

    App_GlobalResources

    编译应用程序的全局资源并生成资源程序集。应用程序的 Bin 文件夹中的任何程序集都链接到资源程序集。

    App_WebResources

    创建并编译 Web 服务的代理类型。所生成的 Web 引用程序集将链接到资源程序集(如存在)。

    Web.config 文件中定义的配置文件属性

    如果应用程序的 Web.config 文件中定义了配置文件属性,则生成一个包含配置文件对象的程序集。

    App_Code

    生成源代码文件并创建一个或更多个程序集。所有代码程序集和配置文件程序集都链接到资源和 Web 引用程序集(如果有)。

    Global.asax

    编译应用程序对象并将其链接到所有先前产生的程序集。

    在编译应用程序的顶级项之后,ASP.NET 将根据需要编译文件夹、页和其他项。下表描述编译 ASP.NET 文件夹和项的顺序。

    说明

    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 将在重新启动应用程序域和加载新的程序集之前,从现有应用程序域和旧的程序集中为所有挂起的请求提供服务。

    HTTP 模块

    ASP.NET 应用程序生命周期可通过 IHttpModule 类进行扩展。ASP.NET 包含若干实现 IHttpModule 的类,如 SessionStateModule 类。您还可以自行创建实现 IHttpModule 的类。

    如果向应用程序添加模块,模块本身会引发事件。通过使用 modulename_eventname 约定,应用程序可以在 Global.asax 文件中预订这些事件。例如,若要处理 FormsAuthenticationModule 对象引发的 Authenticate 事件,可以创建一个名为 FormsAuthentication_Authenticate 的处理程序。

    默认情况下,ASP.NET 中会启用 SessionStateModule 类。所有会话事件将自动命名为 Session_event,如 Session_Start。每次创建新会话时都会引发 Start 事件。有关更多信息,请参见会话状态概述

     

    源文档 <http://msdn2.microsoft.com/zh-cn/library/ms178473(VS.80).aspx>

     

    #9楼[楼主]
    Asp.net 应用程序生命周期 页面生命周期的中文文档已经贴出,请参考
    感谢楼主,我来顶贴,这样的帖子实际上非常需要新手入门的时候多注意,学习。
    其实根本不用override基类事件,打开trace就能看到这些。我这篇文章里面有说过:
    http://www.cnblogs.com/cathsfz/archive/2006/11/19/564929.html
    不错,好文,楼上说的也对,诱发一次错误也可以看到
    学习
    不错!好文章!学习了!
    #15楼[楼主]
    @Cat Chen
    是的
    但是设置一下断点,一步一步的跟一下印象会深一点,对么?
    好文,不过再讲讲页面有这样生存周期的原理及如何更好的利用这样的生存期模式的话就更好了!
    #17楼[楼主]
    @拼命郎
    写asp.net控件需要对生命周期有一个清晰的理解
    推荐你看看THIN谭震林写的《道不远人 Asp.net2.0控件开发》吧,讲解的不错
    我不是他的托
    确实,WEBFORM太过于复杂,如果不是做控件开发,觉得并没有必要了解那么清楚。
    一直对page页的生命周期和应用程序的生命周期很迷惑,收益不浅,谢谢楼主
    #20楼[楼主]
    @yangxh
    有用就好
    收藏之。
    VERY GOOD
    引用坚强2002:@拼命郎
    <br>写asp.net控件需要对生命周期有一个清晰的理解
    <br>推荐你看看THIN谭震林写的《道不远人 Asp.net2.0控件开发》吧,讲解的不错
    <br>我不是他的托

    偶在看,呵呵,在此提一个问题,我在onint里想动态创建一些控件并为其设置事件,但此时需要权限管理我又不得不需要session,但是oninit里是没有session的,我该咋办,我之所以放到init里是由于动态设置事件
    顶一下
  • 相关阅读:
    [tensorflow] tf.gather使用方法
    Tensorflow Dataset.from_generator使用示例
    np.random.rand()函数
    python类
    os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
    KNN算法
    Qt编写数据可视化大屏界面电子看板11-自定义控件
    Qt编写数据可视化大屏界面电子看板10-改造QCustomPlot
    Qt编写数据可视化大屏界面电子看板9-曲线效果
    闲谈Monaco Editor-基本使用
  • 原文地址:https://www.cnblogs.com/qianyz/p/2453591.html
Copyright © 2011-2022 走看看