ASP.NET页面执行模型和服务器控件生存周期模型

                                                  ASP.NET页面执行模型和服务器控件生存周期模型


      几个月前,我从客户端转到服务器端,平生第一次接触了ASP.NET这个完全可扩展的,基于控件(组件)和事件的高度可重用的服务器端编程架构。现在我可以这样评价它,但是数天前,我却遭受了前所未有的困难,如果你只是使用微软已经写好的服务器控件,你不见得会遇到这样的挫折,但是当那些控件无法满足我们的需求的时候,我们就要动手编写我们自己的控件,然而,其中的困难便迎面而来:页面执行模型和服务器控件的生存周期模型。还好,经过几个周的激烈的攻坚战,终于让我搞明白了,现在写出来和大家分享。
     为了使问题描述的更加详细些,我就从页面的执行说起。
     一、HTTP运行期——在ASP.NET应用中请求处理。
 
 
     
     图中的执行过程如下:
     1.一个客户端代理(比如web浏览器)发出一个http请求。
     2.IIS接收请求并将其交付给ASP.NET ISAPI处理。
     3.ASP.NET 中的HTTP运行期解析该请求来决定调用适合的HTTP处理程序或者HTTP处理程序工厂。它也形成了HTTP模块的一个管线(pipeline)或者次序来处理这个请求。
     4.HTTP模块执行请求的预处理,包括高速缓存的查询和授权。
     5.HTTP执行处理程序或者处理程序工厂,进行与请求真正相关的处理工作。
     6.在aspx页面请求的情况下,页面实例化一个控件树,同时显示该控件树来形成响应。
     7.HTTP模块执行请求的后期处理。
     8.响应的结果返回客户端。
     HTTP运行期处理客户代理发来的的一个web请求,通过处理它的应用程序中的适当的组件路由请求,然后产生响应发回请求的客户端。
     进入的HTTP web请求最先有IIS服务器接收,它再把请求基于ASP.NET已注册处理的扩展名送到ASP.NET ISAPI上。一些通用的文件扩展名是由ASP.NET处理的,其中包括.aspx、.asmx、.ashx文件。而ASP.NET运行期就像是在IIS和托管web应用程序之间架起的一道桥梁。
     ASP.NET HTTP运行期为处理请求初始化了很多的对象。HTTP运行期首先初始化一个HttpContext(Http上下文)对象的实例,它包含了当前正在处理的请求信息,接着创建正在处理逻辑中涉及到的所有其他组件都可以使用的上下文对象。该上下文对象经过上图的线性处理链。
     HttpContext对象提供了对请求对象和响应对象的访问,请求对象是HttpRequest类的实例,而响应对象是HttpResponse对象的实例。请求对象代表了由请求应用程序发送到web服务器的数据,并包含了如请求的URL、任何发出的数据和Http头部的一类信息。响应对象包含了从web服务器送到请求应用程序的输出内容(例如html流)。它允许处理请求中涉及的组件在输出流中生成内容,并增加内容的类型信息,例如MIMI类型。HttpContext对象还提供了请求处理程序持续期间对各种不同服务的访问。这些服务包括应用程序和会话状态,ASP.NET高速缓存和用户身份信息。
     二、页面执行模型。
     正如前述,由IIS进入的请求,把请求传给ASP.NET中的HTTP运行期进行处理。页面执行模型是由一个HTTP处理程序工厂开始的,它注册HTTP运行期以为所有.aspx文件处理请求。一面处理工厂负责创建一个Page对象的实例,这是将最终处理请求所生成响应结果的HTTP处理程序。
     首先页面处理程序工厂尝试在与请求的.aspx文件相关的ASP.NET高速缓存内查找以前编译过的页面类。当在查找失败时,就像第一次请求一样,处理程序工厂将读取和解析文件,并创建一颗解析树,解析树类似于控件树,但是不是控件树(因为不包含控件),它包含称为控件生成器的对象实例。控件解析器包含了在解析过程期间收集到的相关控件的信息,然后通过Page指令中的Language attribute,用与页面相关的语言把解析树转换为代码。然后页面处理程序工厂调用相关的编译器(如c#编译器)动态地编译从Page中得到的类。页面处理程序工厂还将新建的类防止到asp.net高速缓存中,并把高速缓存记录和文件相关性关联起来,文件相关性监视.aspx文件的变化,如果一旦.aspx文件发生变化,高速缓存就会丢弃以前的缓存,将下次请求作为一个全新的请求。
     执行模型如下图表示:


 
     第一个请求:
     1.web客户端发出一个http请求,他被http运行期处理并发送到http处理工厂来处理
     2.页面http处理工厂解析被请求的.aspx文件并动态的生成代码来表示解析树
     3.生成的代码被编译,最终的类被储存在高速缓存中。
     4.创建动态生成类的一个实例,并且以http处理程序的形式用来处理进入的请求
     5.执行示例化的页面,处理生成的控件树,单个的控件生成了相应的html输出
     6.最终的响应被发送到客户端
     第二个请求:
     7.web客户端(可能是前一个客户端,也可能不是)向同一个页面发出http请求
     8.页面的http处理程序工厂成功的查询到了前一个请求存储在高速缓存中的类
     9.创建前一个被高速缓存的page类的实例,并作为http处理程序来处理进入的请求,如4和5
     10.最终的相应被发送回第二个请求的客户端
     页面处理程序工厂将动态编译的页面类实例化,由新建的实例处理进入的请求。页面执行模型的最重要的一点就是页面作为完全编译的代码被执行。页面执行了从解析树中生成的代码,这些代码创建并处理源aspx文件内的控件树。控件树拥有它自己的生命周期:初始化、装载、生成和释放。在处理的最后阶段,页面生成自己的响应的内容。
     三、控件的生存周期。
     当浏览器给ASP.NET页面发送请求时,就产生了无状态的http协议的通信,然而,页面框架创建了一个假想的有状态的执行过程,这中过程能够使页面提供与一个连续执行的桌面程序相似的用户体验。为了创建这种假想的持续性,对初始请求之后的每一个后续请求,页面实际上是保存了它的状态,在回传时,再对处理新的请求之前恢复以保存的状态。


 
     如上图为控件的生存周期模型,下面概述一下在每个生存周期阶段,控件都做了什么,以及控件都需要做实现什么。
     •实例化  控件被页面或者另一个控件调用它的实例化构造器所实例化。这个步骤之后所列出的阶段知道加入控件树中才会发生。
     •初始化  在此阶段,控件树中的页面和全部控件通过默认的方式来调用OnInit方法(引发了Init事件),在执行其生命周期之前,页面根据.aspx文件的声明性语法建造了初始的控件树。接着初始化阶段,对声明页面语法中定义的控件属性赋值。在其生命周期的这个时候,控件能够安全的访问置于Controls集合中的子控件,但是不能访问控件层次中父控件或任何其他层次更高的控件,如页面。
     •开始跟踪视图状态  这个阶段发生在初始化阶段的末尾。在此阶段中,页面自动调用控件的TrackViewState方法。TrackViewState方法保证在此阶段之后的使用ViewState字典属性而产生的变化保存在控件的视图状态中。
     •加载视图状态  这个阶段只发生在回传过程中,而不是初始请求中。在此阶段中,控件必须把其状态恢复到它在处理先前的请求结束的情况。在此阶段中,页面调用控件的LoadViewState方法,恢复ViewState字典。
     •加载回传数据  此阶段也只发生在回传处理中。只有在控件通过实现IPostBackHandler接口参与了回传数据处理时,这个阶段才会在回传中发生。在此阶段中页面从中取出客户端通过表单传送的值。
     •加载  直到此阶段开始,控件树中的所以控件都已被实例化,并恢复到先前周期的最后状态。此外,回传控件已经主要用于发送表单数据。因此在此阶段(并不是很早)控件能安全地访问其他层次的控件。在此阶段,控件树中的页面和所以控件都在默认情况下引发onload事件。
     •引发修改事件  此阶段也只发生在回传阶段。 只有控件实现了IPostBackDataHandler接口参与回传数据处理时,此阶段才会发生在回传中。在此阶段控件通过引发事件(如TextBox的TextChanged事件)作为一种信号——其状态由于回传而修改。为了参与此阶段,控件必须实现IPostBackDataHandler接口的RaisePostDataChangedEvent方法。
     •引发回传事件  只用于回传。只有控件实现了IPostBackEventHandler接口时,此阶段才会发生在回传阶段。在此阶段可以通过实现IPostBackEventHandler接口的RaisePsotBackEvent方法来实现逻辑,以便把客户事件映射到服务器端。Button控件就是一个例子,它可以在服务器端引发Click事件,使页面开发者能处理客户端回传事件。
     •预生成  在此阶段,执行在生成前所有的准备工作。控件树中的页面和所有的控件都在此阶段引发各自的PreRender事件。
     •保存状态视图  在此阶段,页面将自动保存ViewState字典。以备在以后的请求中恢复,注意:任何在aspx页面声明文件中的属性都不会保存到字典,除非在之前其他阶段动态的修改过属性。如果控件不维护状态视图,或者控件的状态交由ViewStae管理,则不必为此附加执行逻辑。
     •生成  在此阶段,页面递归地调用控件树中所有控件的Render方法,此阶段过后页面也就生成了能在浏览器中显示的html流。
     •卸载  在此阶段页面通过执行Page_Onunload方法,来执行清楚工作,在此阶段,页面和所以的控件都在默认的情况下引发了各自的unlond事件。
     •释放  在此阶段释放了页面任何用过的资源,如果在自己开发的控件中占用大量的资源应该通过重载Dispose方法来释放掉。

 

      这篇文章只是概述了page 执行模型和 web contorl的生存周期模型,对于新手可能有许多地方还是不太明白,接下来的一些日子,我会发表一些实际的例子来表述控件的生存周期。敬请关注!另外这其中有些是我个人的理解,如有和你们想法不同的地方,欢迎提出,我们共同探讨!

  

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值