Asp.net页面生命周期

前言                                    

 本篇记录的是Asp.net页面生命周期,也就是管道模型的最末端HttpHandler的生命周期。(Page继承了IHttpHandler接口。想了解管道模型,请参考asp.net管道模型(管线模型)之一发不可收拾)。如有不足请大家指出^_^!!

 本篇主要参考:ASP.NET编程模型之页面生命周期十一步详解

        ASP.NET编程模型之ASP.NET页面生命周期图解

       《亮剑.net 深入体验与实战精要》

正文                                    

1.页面实例化之前:Asp.net工作进程会确定是否需要分析和编译页面从而开始生命周期,或是否从缓存中读取已生成好的html页面而不开始生命周期;

2.页面实例化:这个阶段会检查该请求是否为回传,并且设置IsPostBack和UICulture属性等。(2012/9/27补充:此时HttpContext.Current.Session对象未实例化,所以无法引用)

3.页面预初始化(OnPreInit):此阶段a.将初始化在aspx文件声明的服务器控件和页面,当然也可以在这里生成动态服务器控件,并生成
页面的控件树;b.动态设置Theme属性。注意此时只是初始化了服务器控件和页面的框架和声明时设置的属性,而viewstate等还没有恢复,也不存
在回传值(但可以通过Request.Form来获取有效控件的回传值,只是还没复制到控件实例中。因为Request对象不是在HttpHandler
中实例化的,具体请参考:asp.net管道模型(管线模型)之一发不可收拾)。

4.页面初始化(OnInit):读取页面和控件的值,生成动态服务器控件。(2012/5/25补充:初始化后:Begin Tracking View State,此后的viewstate才会保存起来 )

(2012/9/27补充:此时HttpContext.Current.Session已经实例化了)

5.页面初始化完成(OnInitComplete):处理要求先完成所有初始化工作。(暂时不清楚哪些功能点要用到它)

6.加载页面状态(LoadPageStateFromPersistenceMedium):该事件只在IsPostBack为True时触发
(所以IsPostBack等属性要在实例化时就设置好了!)。注意该事件加载的是页面状态而不单单是ViewState,页面状态
(PageState)包含ViewState和ControlState。其中ViewState又有页面的ViewState和控件的
ViewState,而这里加载的ViewState中包含了这两种。该事件是管加载,不管恢复,所以执行该方法后控件和页面依然没有回传值和
ViewState值。(这里的ControlState具体用法有待研究:2012/5
/25补充:ControlState是一种特殊的ViewState,即使页面或网站禁用了ViewState,ControlState依然起作用。
在自定义控件时,涉及到的方法有LoadControlState、SaveControlState,要使用ControlState必须向页面注册
ControlState,注册方法为:Page.RegisterRequiresControlState(this),这样就可以用
ControlState保存控件的信息了!)

7.恢复页面ViewState(LoadViewState):如果上一步中加载的ViewState中含有页面ViewState那么该事件将
会被触发,否则跳过。什么是页面ViewState呢?其实就是直接以ViewState[key]=value形式设置的ViewState。恢复后调
用ViewState[key]就得到上次请求设置的值了!

8.恢复控件ViewState(控件的LoadViewState):每个服务器控件的祖父均为Control类,服务器控件就是通过继承
Control类的LoadViewState方法来恢复ViewState的。同样如果在第6步中加载的ViewState含有该控件的
ViewState,那么就执行该方法;

9.获取控件的回传值并设置控件到相应的属性上(控件的LoadPostData):存在回传值的服务器控件均继承了
IPostBackDataHandler接口,并实现了LoadPostData方法和RaisePostDataChangedEvent事
件。 protected override bool LoadPostData(string postDataKey,
System.Collections.Specialized.NameValueCollection
postCollection),其中参数postDataKey为服务器控件的服务器端ID,用于标识取哪个控件的回传值;参数
postCollection是所有回传值的集合,就是Request.Form里面有的这里都有。该方法会在postCollection中获取
postDataKey对应的回传值,然后跟第8步中恢复的ViewState值作对比(如果没执行第8步,则与控件的默认值作对比),如果不同则返回
true,否则返回false。2012/09/04新增:对于返回true的对象,将会保存其RaisePostDataChangedEvent事件到一个数组中,供后期使用。

好了,现在在aspx文件上声明的控件的状态和回传值都已经恢复和设置到控件实例中了。让我们继续探讨吧!

10.页面加载(OnLoad==Page_Load):我想大家都十分熟悉这个事件了,这里我们可以随心所欲地操作aspx文件上声明的控件了,
但除了在该事件中实例化的服务器控件。在该事件中可以实例化服务器控件并将其加入到页面的控件树中,就是form1.Controls.Add(服务器控
件实例)。如果IsPostBack为True,因为此时实例化的控件没有参与步骤8到9,所以当该控件加入到页面控件树时就会进入步骤8,执行完继续执
行Page_Load的其余代码,但这些控件还没获得回传值;

  注意点1:以下情况实例化控件的话,将无法直接通过“控件变量.属性”的形式获取实例化控件的回传值,要通过this.form1.FindControl等形式获取。

1 protected void Page_Load(object sender, EventArgs e)
2 {
3     TextBox tbx = new TextBox();
4     this.form1.Controls.Add(tbx);
5 }

可以改成这样来直接获取

public partial class _Default : System.Web.UI.Page
{
   TextBox tbx = null;

    protected void Page_Load(object sender, EventArgs e)
    {
        tbx = new TextBox();
        this.form1.Controls.Add(tbx);
     }
}

注意点2:对于DropDownList控件

   当在aspx声明DropDownList控件,在Page_Load事件中添加option项可以这样写

 

protected void Page_Load(object sender, EventArgs e)
{
     if(!IsPostBack)
     {
         ddl.Items.Add(new ListItem("1","1"));
         ddl.Items.Add(new ListItem("2", "2"));
      }
}

回传时会发现这两个option项均保存在控件ViewState中。

       当在Page_Load事件中实例化DropDownList并加入页面控件树时(如下面法)

 

protected void Page_Load(object sender, EventArgs e)
{
      DropDownList ddl = new DropDownList();
      if (!IsPostBack)
     {
         ddl.Items.Add(new ListItem("1", "1"));
         ddl.Items.Add(new ListItem("2", "2"));
      }
      this.form1.Controls.Add(ddl);
}

回传时发现这两个option项均没有保存在控件ViewState中。因此导致无法恢复option项。因此必须每次Page_Load都完全重新生成一次,如下:

protected void Page_Load(object sender, EventArgs e)
{
     DropDownList ddl = new DropDownList();
     ddl.Items.Add(new ListItem("1", "1"));
     ddl.Items.Add(new ListItem("2", "2"));
     this.form1.Controls.Add(ddl);
}

至于ms为什么这样设计还有待研究,求解答!

2012/5/25更新:

 对于上面的问题在上阵子学习自定义控件时找到了答案,现在补充一下吧!这里涉及到
容易犯的误区——只要开启的ViewState,一切服务器控件的数据都将保存在ViewState中。其实不是这样,只有该控件执行了
TrackViewState后,在该控件上设置/修改的数据才会保存到ViewState中。那什么是TrackViewState呢?那么我们要认识
一个接口IStateManager,asp.net规定每个需要使用ViewState的类必须继承IStateManager接口,而
TrackViewState就是这个接口里面的方法,而该接口中还有一个只读属性
IsTrackingViewState,TrackViewState就是用来修改IsTrackingViewState返回的值的,只有IsTrackingViewState返回true,那么该控件的值才会在SaveViewState中保存到ViewState中(当然我们可以重写的时候让IsTrackingViewState永远返回false,那么控件的数据就无法保存到ViewState了)。
而TrackViewState的是在控件初始化的末期执行的,而上面的情况ddl先经历实例化,然后就添加列表项,在添加到页面控件树里面,当加入页面
控件树时ddl会马上追赶页面的生命周期到达“加载”这个阶段,当然ddl的TrackViewState在这时已经执行了,所有后面对ddl的修改将保
存到ViewState中,但应添加列表项的操作时再TrackViewState执行前的,所以列表项就不会保存到ViewState中。如果先把
ddl添加到页面控件树再添加列表项,那么列表项将会保存到ViewState当中去。

  再补充——生命周期追赶:在后台代码中动态生成控件时,控件会处于其生命周期中的“实例化”阶段,当加入到页面控件树时就会同步到页面当前的生命周期阶段,而两个阶段之间的各个阶段控件都会经历

11.获取在Page_Load中实例化的控件的回传值并设置控件到相应的属性上(控件的LoadPostData):过程跟步骤9一样,只是给在Page_Load中实例化的控件一个得到回传值的机会,要好好珍惜哦!

12.控件回传值变化事件(RaisePostDataChangedEvent):2012/09/04修改:这里会遍历第9步和第11步中的保存RaisePostDataChangedEvent事件的数组,并逐一执行事件的处理函数对于第9步和第11步返回true的控件就会触发该事件,注意这里是一堆控件一起触发事件。(具体用途有待研究)

13.RaisePostBackEvent:但点击Button和ImageButton时会触发;(具体作用有待研究)

2012/5/25补充:

  RaisePostBackEvent不单单是点击Button和
ImageButton时会触发,其实只要回传操作都会触发。Asp.net规定能实现通过点击、值变更等操作而触发回传操作的控件必须继承
IPostBackEventHandler接口,而RaisePostBackEvent就是该接口的方法。控件的所有上述回传操作都会触发RaisePostBackEvent方法,然后根据实际情况分配给不同的函数去处理。对于页面,页面上所有控件的上述回传操作均会触发RaisePostBackEvent方法,然后根据参数的不同由不同的函数去处理,而我们平常习惯在Asp:Button上OnClick写事件处理函数,其实该事件处理函数就是通过RaisePostBackEvent根据不同的参数来指定该函数来处理回传的。

14.页面验证(Validate):在IsPostBack为True并且页面有验证web服务器控件时触发。

15.回发事件处理:如Button的Click事件处理程序;注意——若在这里添加服务器控件,那么将不会触发loadviewstate和loadpostback。

16.页面加载完成(OnLoadComplete):此时页面加载完成了,服务器控件均完整并可用;

17.页面预呈现(OnPreRender):这里是设置控件属性并该设置能保存到ViewState的最后地方,当然也可以在第18步中设置;在
该方法执行前会先执行页面和控件的EnsureChildControl方法和执行设置了DataSourceID属性的控件的DataBind事件。

18.页面预呈现完成(OnPreRenderComplete);

17.保存页面状态(SavePageStateToPersistenceMedium):这里默认会将页面ViewState、控件
ViewState和控件ControlState等按base64编码序列化,保存到一个隐藏控件中。经过该事件后,再设置控件的属性(如
TextBox的Text、CssClass属性等,ViewState会保存控件的所有属性),结果能呈现到客户端,但回传时控件的ViewState依然为旧值;页面ViewState道理一样。如果设置了ViewState分块保存的话,会将ViewState分块保存在多个隐藏控件中。如下

如果隐藏域中的数据量过大,某些代理和防火墙将阻止对包含这些数据的页的访问。由于最大数量会随所采用的防火墙和代理的不同而不同,较大的隐藏域可能会出现偶发性问题。如果您需要存储大量的数据项,可以打开视图状态分块,这样会自动将数据分割到多个隐藏域。

ASP.NET框架提供了MaxPageStateFieldLength属性,用来获取或设置页状态字段的最大长度。其属性值表示页面状态字段的最大长度,以字节为单位。

微软官方网站以及很多文章介绍说,通过设置Page.MaxPageStateFieldLength属性可以指定块的最大字节数,且MSDN明确
说明此属性是公有的,笔者在VS 2005和VS
2008下测试结果是Page下面根本没有这个属性,所以采用在配置文件Web.Config中实现,如下:

  1. <system.web> 
  2.     <pages maxPageStateFieldLength="100" />      
  3. <system.web> 

当MaxPageStateFieldLength属性设置为正数时,发送到客户端浏览器的视图状态将分为多个隐藏字段,并且每个字段的值都小于在
MaxPageStateFieldLength属性中指定的大小;而如果MaxPageStateFieldLength属性设置为负数(默认值),则
表示不应将视图状态字段分成多个块区。另外,如果将MaxPageStateFieldLength设置非常小,会导致性能降低。

18.呈现(Render):此时对页面请求的处理算是告一段落,这里会将整个页面转换成html页面并保存到一个HtmlTextWriter对
象中,该对象会传递到Response.OutputStream中返回给客户端;(可以在这事件中截取转换后的html进行加工,然后将结果html字
符串写到Response.OutputStream中。后置ViewState就是这样做哦!具体请参考:网页优化系列三:使用压缩后置viewstate

19.释放资源(Dispose):执行销毁控件前的所有最终清理操作。在此阶段必须释放对昂贵资源的引用,如内存的退出、数据库的连接等。

20.卸载(OnUnload):页面生命周期正式结束。

 

结束语                                   

  Asp.net页面生命周期中还有很多地方值得深入学习,这里只是作个小结和介绍,以后慢慢完善吧!!

时间: 2024-11-01 04:52:49

Asp.net页面生命周期的相关文章

关于ASP.NET页面生命周期的整体把握

对于每一个.NET程序员,对于ASP.NET页面生命周期都有一定的了解和把握.关于一些细节方面请参考 http://blog.sina.com.cn/s/blog_5f7aa2970100d5h4.html,内容比较详尽,本文将不再概述.本文主要是从 继承以及视图状态,事件,委托,容器控件以及子控件这些方面来把握和控制整体的页面生命周期. 先看下下面4个相关页面的代码(为降低复杂度,很多代码被删减与精简,仅提供最基本的操作代码).仅仅 几个文件,先看下整体文件的布局,有一个整体的把握.    

记不住ASP.NET页面生命周期的苦恼

介绍 对于ASP.NET开发者,理解ASP.NET的页面生命周期是非常重要的.主要是为了搞明白在哪里放置特定 的方法和在何时设置各种页面属性.但是记忆和理解页面生命周期里提供的事件处理方法(method)非常困 难.互联网上有很多关于页面生命周期内部机制的文章,所以本文只准备简单覆盖技术的基础部分,更主 要的目的是给大家提供一个简单得记忆页面生命周期的方法. 准确的记忆ASP.NET页面生命周期每一个阶段发生了什么事情是比较困难的,一种便于记忆的方法是根 据各个阶段的名字组合出一个缩写.微软的文

asp.net页面生命周期详解_实用技巧

Asp.net是微软.Net战略的一个组成部分.它相对以前的Asp有了很大的发展,引入了许多的新机制.本文就Asp.net页面的生命周期向大家做一个初步的介绍,以期能起到指导大家更好.更灵活地操纵Asp.net的作用.当一个获取网页的请求(可能是通过用户提交完成的,也可能是通过超链接完成的)被发送到Web服务器后,这个页面就会接着运行从创建到处理完成的一系列事件.在我们试图建立Asp.net页面的时候,这个执行周期是不必去考虑的,那样只会自讨苦吃.然而,如果被正确的操纵,一个页面的执行周期将是一

详解ASP.NET页面生命周期事件_实用技巧

下面是ASP.NET页面初始的过程:1. Page_Init();2. Load ViewState;3. Load Postback data;4. Page_Load();5. Handle control events;6. Page_PreRender();7. Page_Render();8. Unload event;9. Dispose method called; 下面对其中的一些过程作下描述:1. Page_Init();这个过程主要是初始化控件,每次页面载入执行这个初始过程,

详解ASP.NET页面生命周期_实用技巧

ASP.NET页面运行时候,页面将经历一个生命周期,在生命周期中将执行一系列的处理步骤.包括初始化.实例化控件.还原和维护状态.运行时间处理程序代码以及进行呈现.熟悉页面生命周期非常重要,这样我们才能在生命周期的合适阶段编写代码.如果我们能在写代码的时候想着我们现在是在做生命周期的哪一步那将是非常好的. 几个代表性的问题 在开始的时候我们先思考几个问题,看看我们在描述完页面生命周期的时候,能不能回答上这几个问题 1.为什么在服务器端能通过this.textbox1.Text获取到用户提交过来的数

一起谈.NET技术,关于ASP.NET页面生命周期的整体把握

对于每一个.NET程序员,对于ASP.NET页面生命周期都有一定的了解和把握.关于一些细节方面请参考http://blog.sina.com.cn/s/blog_5f7aa2970100d5h4.html,内容比较详尽,本文将不再概述.本文主要是从继承以及视图状态,事件,委托,容器控件以及子控件这些方面来把握和控制整体的页面生命周期. 先看下下面4个相关页面的代码(为降低复杂度,很多代码被删减与精简,仅提供最基本的操作代码).仅仅几个文件,先看下整体文件的布局,有一个整体的把握. (一)父类的相

艾伟_转载:温习:ASP.NET页面生命周期

ASP.NET 页面生命周期虽然是最基础的东东,但我发现很多人不能准确地的说出,可能多数程序人员只是对深层技术感兴趣的原因吧?可是如果忘记了最基础的东西,有时会给你的开发制造很大的麻烦.现在把MSDN上的ASP.NET页面生命周期贴出来,大家温习一下吧(温习之前请问一下自己你知道吗): ASP.NET 页运行时,此页将经历一个生命周期,在生命周期中将执行一系列处理步骤.这些步骤包括初始化.实例化控件.还原和维护状态.运行事件处理程序代码以及进行呈现.了解页生命周期非常重要,因为这样做您就能在生命

IIS处理Asp.net请求和Asp.net页面生命周期说明

首先我们要弄清楚两个非常重要的概念: 1, worker process(w3wp.exe). worker process管理所有的来自客户端的请求并给出响应.它是IIS下asp.net应用程序的核心. 2, application pool. 它是worker process的容器,IIS5及之前的IIS版本均没有application pool的概念.每一个application pool对应着一个worker process,在IIS Metabase中维护着Application Po

Asp.Net页面生命周期(多图)

原文 http://www.cnblogs.com/DotNetEnjoy/archive/2013/04/15/3022672.html asp.net的请求处理模型已经讲完几个星期了,但一直没有时间整理,一来是因为知识点确实繁杂,难以整理,二来了解得也不够清晰,存在一些误区.今天有空写下这篇博文,希望大家指正其中的不足,以便能加深对请求响应的理解. 根据自己理解和老师讲课的内容,花了一张图   1.浏览器实际上是一个Socket客户端,它向服务器发送请求报文 2.请求报文被封装为http请求