ASP.NET 3.5核心编程学习笔记(3):页面的生命周期

  每次客户端请求都会创建页面实例,它的执行使自身及其包含的控件经历页面生命周期的各个阶段。页面的执行起始于HTTP运行库调用ProcessRequest时,该方法将启动页面并控制它的生命周期。

  页面的生命周期可分为三个阶段:建立阶段、回发阶段、终结阶段。每个阶段会有子阶段,分别由若干步骤和事件引发点组成。

页面的建立

  当HTTP运行库实例化一个页面类对当前请求进行处理时,页面的构造函数会生成一个控件树,该控件树会关联到实际的类,这些类是由页面解析器在扫描ASPX源代码后创建的。当请求的处理过程开始时,所有子控件和页面的内部对象(如HTTP上下文对象、请求对象和响应对象等)都会被设置。

  页面生命周期的第一个阶段是确定运行库处理当前页面请求的原因。原因有很多种:常规请求、回发、跨页投递或回调。基于实际的原因,页面对象会配置其内部状态,如果包含被投递的值,还会根据请求的方法(GET或POST)准备该值的集合。在第一个阶段过后,页面便为引发事件来执行用户代码做好了准备。

PreInit事件

  这是ASP.NET 2.0引入的事件,它是页面生命周期的入口点,该事件被引发时,页面尚未与母版页和主题相关联。但页面滚动条位置已被恢复,被投递的数据变为可用,且所有的页面控件已被实例化,其属性也已基于ASPX源中的默认值进行了设置(注意,如果没有在aspx源中显式指定,这时的控件是没有ID的)。在这个阶段中,可对母版页进行调换,或对主题进行编程。IsCallback、IsCrossPagePostback和IsPostBack会在这时被设置。

Init事件

  在这个阶段,母版页和主题会被设定,不能再被更改。页面处理程序(即Page类的ProcessRequest方法)开始执行,对所有子控件进行迭代,使其有机会在上下文环境下初始化它们的状态。所有子控件都有自己的OnInit方法,后者以递归方式被调用。对于控件集合中的每个控件,都将设置命名容器和特定ID(如果没有在源中分配的话)。

  Init事件首先会处理子控件,然后是页面。在这个阶段,页面和控件通常开始加载其部分状态,此时,视图状态尚未被恢复。

InitComplete事件

  该事件是ASP.NET 2.0中引入的,用于指示初始化子阶段的结束。对于页面来说,在Init和InitComplete事件间只有一个操作会执行--启用视图状态的变更跟踪功能。视图状态的跟踪是这样一种操作:它最终使控件能够真正地将所有以编程方式添加到ViewState集合中的值,存储在持久性介质中。简而言之,对于没有实施视图跟踪的控件,添加到其ViewState中的值将在回发间丢失。

  在控件引发各自的Init事件后,视图状态跟踪会立即启动,页面也不例外(归根结底,页面也是一种控件)。

  注意:在InitComplete前,任何写入ViewState集合的值在下一次回发时都不再可用。

视图状态的恢复

  如果页面因回发而被处理(即IsPostBack属性为true),隐含字段__VIEWSTATE的值会被恢复。隐含字段__VIEWSTATE用于在请求结束时保存所有控件的视图状态。页面的整体视图状态是一种调用上下文,包含页面每个组成控件上一次发往浏览器的状态信息。

  在这个阶段,每个控件都可恢复其上一次请求时的状态。视图状态的恢复过程不会引发任何事件,如果需要对此进行定制,则必须重写LoadViewState方法(该方法在Control类中为protected virtual成员)。

处理被投递的数据

  HTTP请求中打包的所有客户端数据(即所有定义在<form>标签中输入字段的内容)将在此被处理。被投递数据通常采用如下形式:

  TextBox1=text&DropDownList1=selectedItem&Button1=Submit

  该字串用键/值对被“&”分隔,这些值将被加载到一个内部使用的集合当中。页面处理程序会试图寻找被投递集合中的名称与页面控件ID的匹配项,如果找到匹配项,处理程序会检查该服务器控件是否已实现IPostBackDataHandler接口。如果已实现,将调用该接口的LoadPostData方法更新该控件状态。如果该方法返回true表示状态已被更新,该控件将被添加到一个独立的集合中,等待进一步指示。

  如果没有找到与被投递名称对象的服务器控件,它将被置于一临时的独立集合中,稍后再试。

PreLoad事件

  PreLoad事件是ASP.NET引入的,仅用于指示页面已完成系统级的初始化,即将进入另一个阶段。接下来的阶段会为页面中用户代码的执行提供机会,为执行和呈现该页面做进一步配置。

Load事件

  Load事件首先由页面引发,然后以递归方式分别由所有子控件引发。这时,页面中的控件树会被创建,各控件的状态完全反映之前的状态,并获得了从客户端投递过来的所有数据。对于执行处理逻辑和页面行为的初始化代码,页面已做好准备。这时访问控件属性和视图状态是绝对安全的。

处理动态创建的控件

  当页面中所有控件完成了显示前的初始化后,页面处理程序会对那些没有与现有控件对应的被投递数据做再次尝试。该行为会对之前搁置的键/值对再次处理。这一特殊的方式提供了一种不可思议的特殊方案--使用动态创建的控件:就是将控件动态地添加到页面的树中。如前所述,每次回发,页面都要根据状态重新生成,因而有关动态创建控件的信息会丢失。另一方面,当页面的窗体提交后,动态控件会被填充合法且有效的信息,并以常规方式投递。根据设计,初始的动态控件的ID不可能与某个服务器控件的ID匹配。然而,ASP.NET会识别Load事件中被创建的控件。这样,在用户代码运行一段之后,便可再次尝试寻找可能的匹配项。

回发的处理

  回发机制是ASP.NET编程的核心,其过程为:将窗体数据投递到原页面,使用视图状态恢复调用上下文(即上一次投递页面后,在服务端生成的控件状态)。

  在页面被初始化,且被投递值也已就位后,便可以引发服务器端的事件。这些事件主要分为两类:第一类事件标志着特定控件在回发间状态发生了改变;第二类事件是在服务器端对引发投递的客户端动作的响应。

控件状态变化的检测

  整个ASP.NET系统隐含了这样一个假设:在浏览器运行的某些HTML标签与活跃在服务器端的某些ASP.NET控件必须存在一一对应关系。<input type="text">和TextBox控件间的对应就是一个例子。为从技术上严格执行,该联系通过相同的ID名称表示。当用户被输入元素键入某些新文本,并将其投递到服务器后,对应的TextBox控件(即与该输入控件ID相同的服务器控件)会被调用,以处理被投递的值。对于所有LoadPostData方法返回true的控件,这时会执行IPostBackDataHandler接口的另一个方法--RaisePostDataChangedEvent方法。该方法发出信号给控件,通过ASP.NET应用程序,该控件的状态已被更改。

服务器端回发事件的执行

  任何有意触发服务器端动作的客户端动作会引起回发。

  页面回发到服务器有两种方式:一是通过提交按钮(即,<input type="submit">);二是通过脚本。HTML提交按钮会由服务器控件Button生成,LinkButton控件及其他一些可回发控件,会将一些脚本插入到客户端页面中,并将自身的某个HTML事件(如onclick)绑定到浏览器HTML对象模型中窗体submit方法上。

  在窗体提交方面,自ASP.NET 2.0开始,Button类获得了一个新属性UseSubmit-Behavior,使页面开发者能够控制客户端相应HTML元素的行为。如果UseSubmitBehavior为false,我们的Button控件输出为<input type="button">,同时,客户端元素的onclick属性会被绑定到预定义的脚本代码上。

LoadComplete事件

  LoadComplete事件是ASP.NET 2.0版引入的,用于通知页面准备阶段的结束。但是子控件不会引发该事件。在引发该事件后,页面便进入了呈现阶段。

页面的终结阶段

  处理过回发事件后,页面便为浏览器生成输出做好了准备。呈现阶段分为两部分:预呈现和标记生成。预呈现这个子阶段由两个事件表征:预处理和投递处理。

PreRender事件

  通过处理该事件,页面和控件可以进行生成输出前的任何更改。页面会首先引发自己的PreRender事件,然后按递归方式引发所有子控件。

PreRenderComplete事件

  由于所有子控件的PreRender事件会以递归方式逐一被调用,因而页面设计者无法知道预呈现阶段是否已完成。为此,ASP.NET 2.0版本引入此事件。

SaveStateComplete事件

  在每个控件被呈现输出,为页面生成标记前的一段时间里,要将当前页面的状态存储在视图状态介质中。注意:在该点之后对状态做的任何修改可能会被呈现,但不会被存储,且在下一次回发时无法获得恢复。页面状态存储是一个递归的过程,页面处理程序会遍历整个页面树,逐一调用每个控件的SaveViewState方法,包括页面自身的SaveViewState方法。该方法是protected virtual方法,负责存储当前控件的ViewState字典内容。

  从2.0版开始,ASP.NET为控件提供了另一种状态类型,即所谓的“控件状态”(control state)。控件状态是一种私有状态,不受应用程序控件支配。换句话说,控件的控件状态不能够像视图状态一样以编程方式被禁用。它是另一种状态存储机制,其数据也用于维护原则页间回发,但控件状态的目的是维护控件的必要信息,使其工作正常。也就是说,具有状态行为的属性数据应保存在控件状态中,而用户界面属性数据(如控件的内容)应保存在视图状态中。

  SaveStateComplete事件是ASP.NET 2.0引入的,当页面中所有控件都已完全存储在持久性介质中后,该事件就会被引发。

  页面和独立控件的视图状态会在一个特殊的内存结构中聚集,然后再保存于存储介质中。默认情况下,该持久性介质是一个名为__VIEWSTATE的隐含字段。对存储介质中数据的序列化和反序列化由Page的两个可重写方法处理:SavePageStateToPersistenceMedium和LoadPageStateFromPersistenceMedium。

标记的生成

  针对浏览器的标记生成,会分别由每个子控件自己完成,生成的标记会被存储到一个缓冲中。有几个可重写方法帮助开发者分别对标记生成的阶段进行控件--开始标签、主体、结束标签。没有与该阶段项关联的用户事件。

Unload事件

  呈现阶段之后会进行一次递归调用,引发每个控件的Unload事件,最后是页面自身的Unload事件。Unload事件用于在页面对象被释放前执行最终的清理工作,一般的操作为文件和数据库连接的关闭。

  卸载通知会在页面或控件正要被卸载且尚未被释放前到达。对于实际的页面,重写Page类的Dispose方法,或只处理页面的Disposed事件,是它在内存被释放前做清理工作的最后机会。页面处理程序会调用Dispose方法,释放页面对象。在对Unload事件处理程序的递归调用完毕后会被立即引发。

转载于:https://www.cnblogs.com/free722/archive/2011/04/11/2012642.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值