前言

ASP.NET页面运行时候,页面将经历一个生命周期,在生命周期中将执行一系列的处理步骤。包括初始化、实例化控件、还原和维护状态、运行时间处理程序代码以及进行呈现。熟悉页面生命周期非常重要,这样我们才能在生命周期的合适阶段编写代码。如果我们能在写代码的时候想着我们现在是在做生命周期的哪一步那将是非常好的。

你可能会说我不清楚还不是一样写代码,反正每次都在Page_load里面写代码 然后页面就出来了我管那么多干什么。所谓知其然如果能知其所以然岂不是更吊?我个人认为做ASP.NET B/S开发只要咱们熟悉ASP.NET页面生命周期,熟悉“请求-处理-响应模式,对于一时半儿没有触及到的细节,等真正遇到那个点再去理解它也是毫不费力的。

几个代表性的问题

在开始的时候我们先思考几个问题,看看我们在描述完页面生命周期的时候,能不能回答上这几个问题

1.为什么在服务器端能通过this.textbox1.Text获取到用户提交过来的数据?

2.Page_LoadResponse.Write("hello")查看生成的html代码原文件,hello在哪里?为什么?

3.有一个服务器端的按钮,设置了点击事件,该点击事件什么时候执行?是先执行Page_Load事件还是先执行点击事件?

4.为什么在服务器端通过this.textbox1.Text设置值后,客户端就能显示出来?

看过我上一篇博客【深入ASP.NET原理系列】--ASP.NET请求管道、应用程序生命周期、整体运行机制 童鞋可能知道,ASP.NET应用程序周期中PreRequestHandlerExecute事件与PostRequestHandlerExecute事件之间就是我们的页面生命周期了,对于aspx页面就是一系列的打造页面控件树,触发各种页面时间,对于一般处理程序ashx就是直接执行咱们开发者写的ProcessRequest方法了,对于MVC应用程序就是创建控制器工厂,创建控制器对象,调用Action那一套了。

下面主要讲述的就是ASP.NET WebForm中的页面的生命周期了。

我们用反编译工具查看Page类的ProcessRequest方法可以看见先调用了FrameworkInitializeFrameworkInitialize里面就是打造了页面控件树,然后调用了ProcessRequestMain,就开始了执行整个页面生命周期了(其实就是调用了一系列的事件方法)(可能部分图看不见右边,可在新标签页中打开图片)

1.打造页面控件树

FrameworkInitialize内部调用了_buildControlTree()方法

  

上图中左边是前台页面的代码,右边是对应 生成的打造控件树的代码。中间截取的是生成表单那一部分的代码。
下面看一张原理图

  
浏览器的DOM树是根据Html标签生成一个C语言的DOM树,而ASP.NET服务器端是用C#打造的一个控件树,也是按照DOM结构打造的。本质是一样。服务器端所有东西都加到页面对象的控件集合中去了。标签在服务器端有对应的控件对象的时候就用控件对象,没有的时候就使用LiteralControl进行封装。不管是服务器控件还是字符串标签(没有runat="server"的标签)都以控件对象的方式存在前台页面类的控件集合里面。好处就是生成前台页面的html代码的时候,只需要遍历控件集合里面的每一个控件对象的RenderControl方法,每一个控件都会调用自己的Render方法生成对应的Html字符串。那么所有控件的生成的html字符串就还原成一个页面的html代码了。  

2.触发PerformPreInit事件 

    

在所有初始化之前初始化了这个事件,这个事件主要是初始化了主题,初始化了母版页

    

 

    

3.触发InitRecursive事件

  

4.触发LoadAllState()事件

加载页面状态解析ViewState,将页面表单中的ViewState进行反Base64编码,反序列化,存在页面的ViewState属性中

    

5.触发ProcessPostData(this._requestValueCollection, true)事件

 

主要做了两件事
1)将表单里提交过来的控件数据设置给页面对象的控件树中对应控件的属性(给前面打造的控件树里面控件给值),这样在服务器端就可以拿到客户端输入的值了。
2)将表单里面提交过来的值与ViewState中控件原来的值进行比对,不同则表示要触发该控件的Change 事件,则同时将该控件放到一个集合(看源码其实就是changedPostDataConsumers)中。在后续执行过程中遍历改集合依次触发对应控件的Change事件。

6.触发LoadRecursive()事件

大名鼎鼎的Page_Load就是在这里执行的。不过是先执行页面本身的Load事件再执行页面控件的Load事件哦,这时候前面给控件赋的值,表单提交过来的数据,ViewState等等都可以使用了,IsPostBack的原理就是判断是否有name为__VIEWSTATE的数据提交过来

7.再次触发ProcessPostData(this._leftoverPostData, false)事件

这个事件我在网上看了很多人说是将第一次遗漏下来的,第一次执行ProcessPostData没有涉及到的控件进行处理,但是并没有说明哪些遗漏下来了。为什么第一次没处理了? 最后Google查到是处理我们开发者在页面的Page_Load方法中添加的控件。在Page_Load中我们可以自己创建控件对象加到页面对应的“C#DOM树中“,如:在Page_Load中写
TextBox txt = new TextBox();txt.ID ="myTxtBox";this.form1.Controls.Add(txt);
这就是把开发者自己创建的控件加在页面的form1的表单中。当然你也可以加上Change事件了创建控件的时候。执行的还是上面那两件事了。则回发的时候可以给开发者在Page_Lod中手动创建的控件还原值
    

8.触发RaiseChangedEvents事件

循环遍历changedPostDataConsumers集合中的所有控件,依次执行控件的非点击回传事件,比如文本框的改变事件等      

9.触发RaisePostBackEvent(this._requestValueCollection)事件

执行按钮点击回传事件或者验证事件,如果有多个按钮,根据回发过来的按钮的 name来判断触发哪个按钮的事件,或者触发该控件的验证事件
  

10.触发PerformPreRenderComplete事件


循环遍历控件树中所有的控件,根据每个控件生成对应的Html代码,把服务器控件渲染成普通的html控件。

11.触发事件SaveAllState事件

将服务器端ViewState集合中的内容(开发者自己加的数据或控件状态信息等)序列化然后Base64编码然后设置到客户端隐藏域__ViewState中

12.RenderControl(this.CreateHtmlTextWriter(this.Response.Output))

把要发送到客户端浏览器的内容设置到Response.Output,应用程序将它发送 到客户端浏览器。

看到这里不知道大家是否已经可以清晰地回答开篇提到的几个问题了,其实就是这些事件执行的先后顺序,页面生命周期了。”前人植树,后人乘凉了"

最后附上生命周期ProcessRequest源码  

【深入ASP.NET原理系列】--ASP.NET页面生命周期的更多相关文章

  1. ASP.NET Web 应用程序及页面生命周期

    以客户端浏览器向 ASP.NET Web 应用程序页面发送请求(Request)为起点,以浏览器收到 Web 服务器的响应(Response)为终点,这一完整的过程被称为"应用程序及页面的生 ...

  2. 【深入ASP.NET原理系列】--ASP.NET请求管道、应用程序生命周期、整体运行机制

    微软的程序设计和相应的IDE做的很棒,让人很快就能有生产力..NET上手容易,生产力很高,但对于一个不是那么勤奋的人,他很可能就不再进步了,没有想深入下去的动力,他不用去理解整个框架和环境是怎么执行的 ...

  3. ASP.NT运行原理和页面生命周期详解及其应用

    ASP.NT运行原理和页面生命周期详解及其应用 1. 下面是我画的一张关于asp.net运行原理和页面生命周期的一张详解图.如果你对具体不太了解,请参照博客园其他帖子.在这里我主要讲解它的实际应用.  ...

  4. WebForm页面生命周期及asp.net运行机制

    1.先上几张原理图着重理解: 现在针对第四副图原理进行解析: 流程: 1.浏览器发送请求 2.服务器软件(IIS)接收,它最终的目的就是为了向客户输出它请求的动态页面生成的html代码. 3.服务器不 ...

  5. [ASP.NET MVC2 系列] ASP.Net MVC教程之《在15分钟内用ASP.Net MVC创建一个电影数据库应用程序》

    [ASP.NET MVC2 系列]      [ASP.NET MVC2 系列] ASP.Net MVC教程之<在15分钟内用ASP.Net MVC创建一个电影数据库应用程序>       ...

  6. Asp.net页面生命周期详解任我行(2)-WebForm页面生命周期WEBFORM_ASPNET控件树的生成和作用

    摘要 页面类是如何结合后台文件类生成整个页面的HTML的代码和后台输出的代码输出到浏览器中呢?这就牵扯到Asp.net页面生命周期中一个很重要的概念控件树.服务器以反射的方式创建了页面类对象 内容 我 ...

  7. ASP.net 页面生命周期

    ASP.NET 页面生命周期 Page_Preinit(); 在页初始化开始时发生 Page_Init(); 在所有控件初始化且应用外观设置后引发 Page_InitComplete(); 在页初始化 ...

  8. [转]ASP.NET应用程序生命周期趣谈(四) HttpHandler和页面生命周期

    在之前的三篇文章中,我们还算简明扼要的学习了asp.net的整个生命周期,我们知道了一个Request进来以后先去ISAPI Filter,发现是asp.net程序后又ASPNET_ISAPI.dll ...

  9. asp.net页面生命周期

    Asp.Net页面生命周期 本文转载自:http://www.cnblogs.com/xhwy/archive/2012/05/20/2510178.html 一.什么是Asp.Net页面生命周期 当 ...

随机推荐

  1. Atitit.url 汉字中文路径  404 resin4 resin  解决  v2 q329

    Atitit.url 汉字中文路径  404 resin4 resin  解决  v2 q329 1. Pluginx机制1 2. Code1 3. 参考4 1. 原理 过滤器  ,,拦截jpg  w ...

  2. An interesting experiment on China’s censorship

    This paper presented a very interesting topic. Censorship in China has always drawn people's attenti ...

  3. Java笔试题(一)

    一. 选择题(共50题,每题2分,共100分.多选题选不全或选错都不得分.) 7. 以下说法错误的是()/*这个我感觉是全对,谁知道哪个错啦,讲解下,非常感谢*/A) super.方法()可以调用父类 ...

  4. tomcat中的JSP引擎

    jsp文件解析成class文件过程需要利用tomcat的jasper组件. Jasper是tomcat中使用的JSP引擎,在Tomcat 6中使用的是Jasper 2,相对于原来的版本作了不少的改进, ...

  5. Java核心:类加载和JVM内存的分配

    类的加载: 指的是将class文件的二进制数据读入到运行时数据区(JVM在内存中划分的) 中,并在方法区内创建一个class对象. 类加载器: 负责加载编译后的class文件(字节码文件)到JVM(J ...

  6. 【读书笔记】iOS-ARC-循环引用-解决办法

    一,循环引用最常见的代码类型. - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading ...

  7. iOS 学习 - 13.微信分享链接、QQ 分享图片

    准备工作---原文来自这个 首先要在微信开放平台申请 AppID 和 QQ ID(我第一天晚上申请的,第二天中午就通过了),接着导入 SDK,也就是3个 .h 和一个 .a 文件,详情见这里 如果你是 ...

  8. symfony2 路由工作原理及配置

    1.路由是程序的方法和URL的一一映射.

  9. 我参加了51CTO博客大赛,求投票!

    我是张传波,也是Fireball(火球). 我参加了51CTO博客大赛,距离网络投票截止没有几天了,求投票!我的参赛链接:http://blog.51cto.com/contest2013/82313 ...

  10. 预写式日志(Write-Ahead Logging (WAL))

    SQL Server中使用了WAL(Write-Ahead Logging)技术来保证事务日志的ACID特性.而且大大减少了IO操作. WAL的核心思想是:在数据写入到数据库之前,先写入到日志.再将日 ...