简介
        ASP.NET是微软.NET战略的一个组成部分,它相对以前的ASP有了很大的发展,引入了许多的新机制。本文就ASP.NET页面的生命周期向大家做一个初步的介绍,以期能起到指导大家更好、更灵活地操纵ASP.NET的作用。
        当一个获取网页的请求(可能是通过用户提交完成的,也可能是通过超链接完成的)被发送到Web服务器后,这个页面就会接着运行从创建到处理完成的一系列事件。在我们试图建立ASP.NET页面的时候,这个执行周期是不必去考虑的,那样只会自讨苦吃。然而,如果被正确的操纵,一个页面的执行周期将是一道有效而且功能强大的工具。许多开发者在编写ASP.NET的页面以及用户控件的时候发现,如果知道整个过程中发生了什么以及在什么时候发生将对完成整个任务起到很重要的帮助作用。下面我就向大家介绍一下一个ASP.NET页面从创建到处理完成过程中的十个事件。同时,也向大家展示如何在这些事件中添加自己的代码以达到预定的效果。

1.初始化对象
        一个页面的控件(以及页面本身)最初应被正确的初始化。通过在你的C#文件的构造函数中声名所有对象(如图1所示),页面就知道要创建多少对象以及它们的类型。一旦你在你的构造函数中声名了所有的对象,你就可以通过继承类、方法、事件或是属性访问它们。然而,如果你的一些对象是在Aspx文件中指定的一些控件,那么这些控件就没有属性可言了。同时,通过代码访问它们会产生一些意外的错误,因为这些控件实例是没有一个确定的创建顺序的(如果它们是被一起创建的)。还有,你可以通过OnInit来重载初始化事件。


图1 控件基于声明被初始化

2.加载视图状态数据
       在初始化事件后,所有控件只可以通过它们的ID被引用访问(因为还没有相应的文档对象模型)可使用)。在LoadViewState这个事件中,所有的控件将获得它们的第一个属性:Viewstate属性。这个属性最终将被返回给服务器以判断这个页面是已经被用户访问完毕还是仍然在被用户所访问。Viewstate属性以“名称/值”对的字符串方式被保存,它包含了控件的文本以及值等信息。该属性被存储在一个隐藏的<input>控件的值属性里,在请求页面时被传递。这种方式比起ASP 3.0的维持、判断页面状态的方式有了很大的进步啊。还有,你可以重载LoadViewState事件函数来对相应的控件进行值设定。图2是一个例子:


图2 LoadViewState被激发时,适当的视图数据被填充到控件中

 3.LoadPostData处理Postback数据
       在页面创建的这个阶段,服务器对页面上的控件提交的表单数据(在ASP.NET中称Postback数据)进行处理。当一个页面提交一个表单时,框架就在每个提交了数据的控件上执行一个IPostBackDataHandler接口操作。然后页面执行LoadPostData事件,解析页面,找到每个执行了IpostBackDataHandler接口操作的控件,并用恰当的Postback数据更新这些控件状态。ASP.NET是通过用NameValue集中的“名称/值”对和每个控件的唯一的ID匹配来实现这一操作的。所以,在ASP.NET的页面上每个控件必须有一个唯一的ID,不可以出现几个控件共有ID的情况。即使是用户自定义的一些控件,框架也会赋予它们各自唯一的ID的。在LoadPostData事件后,就要执行下面的RaisePostDataChanged事件了。

4.加载对象
        在Load事件中,对象都实例化了。所有的对象第一次被布置在DOM页面(在ASP.NETt中称控件树)里了,并且可以通过代码或是相关的位置被引用。这样,对象就可以很容易的从客户端获得诸如宽度、高度、值、可见性等在HTML中的属性值。在Load事件中,当然还有像设置控件属性等操作的发生。这个过程是整个生命周期中最重要、最主要的,你可以通过调用OnLoad来重载Load事件,图示如下(图3):


图3 OnLoad事件是放置逻辑的理想位置

 5.激发RaisePostDataChanged 事件
       
就像在上面提到的那样,这个事件是发生在所有的控件执行了IPostBackDataHandler接口操作并被正确的Postback数据更新后的。在这个过程中,每个控件都被赋予一个布尔值来标志该控件有没有被更新。然后,ASP.NET就在整个页面上寻找任何已被更新过的控件并执行RaisePostDataChanged事件操作。不过,这个事件是要在所有的控件都被更新了以及Load事件完成后才进行的。这样就保证了一个控件在被Postback数据更新前,别的控件在RaisePostDataChanged事件中是不会被手动改变的。

6.处理客端PostBack事
        当由Postback数据在服务器端引起的事件都完成后,产生Postback数据的对象就执行RaisePostBackEvent事件操作。可是会有这种情况,由于一个控件状态的改变使得它将表单返回给服务器或是用户点击了提交按钮使得表单返回给服务器。在这种情况下应该有相应的处理代码来体现事件驱动这一面向对象(OOP)编程原则。由于要满足呈现给浏览器的数据的精确性要求,在一系列Postback事件中RaisePostBackEvent事件是最后发生的。 在Postback过程中改变的控件不应在执行功能函数被调用后更新。也就是说,任何由于一个预期的事件而改变的数据应该在最终的页面上被反映出来。你可以通过修改RaisePostBackEvent函数来满足你的要求,图示如下(图4):


图4 RaisePostDataChanged和RaisePostBackEvent由IPostBackDataHandler接口定义

 7.预先呈现对象
        可以改变对象并将改变保存的最后时刻就是这一步――预先呈递对象。这样,你可以在这一步对控件的属性、控件树结构等作出最后的修改。同时还不用考虑Asp.net对其作出任何改变,因为此时已经脱离了数据库调用以及viewstate更新了。在这一步之后,对对象的所有修改将最终被确定,不能被保存到页面的viewstate中了。你可以通过OnPreRender来重载这一步。

8.保存ViewState
        所有对页面控件的修改完成后viewstate就被保存了。对像的状态数据还是保留在隐藏的<input>控件里面,呈现给Html的对象状态数据也是从这里取得的。在SaveViewState事件中,其值能被保存到viewstate对象,然而这时在页面上控件的修改却不能了。你可以用SaveViewState来重载这一步,图示如下(图5):


图5 在OnPreRender中值被设置给控件。在SaveViewState中,值被设置给视图状态对象。

 9.呈现HTML
        运用HTML创建给浏览器输出的页面的时候Render事件就发生了。在Render事件过程中,页面调用其中的对象将它们呈递给HTML。然后,页面就可以以HTML的形式被用户的浏览器访问了。当Render事件被重载时,开发者可以编写自定义的HTML代码使得原先生成的HTML都无效而按照新的HTML来组织页面。Render方法将一个HtmlTextWriter对象作为参数并用它将Html在浏览器上以网页的形式显示。这时仍然可以做一些修改动作,不过它们只是客户端的一些变化而已了。你可以重载Render事件,图示如下(图6):


图6 Render事件通过HtmlTextWriter对象为浏览器产生定制HTML

 10.销毁对象
        当页面的HTML呈现后,对象被释放。在Dispose事件中,你可以清除任何在页面创建中构造的对象或者引用。在这里,所有的处理都已经被执行,你可以安全的释放任何还存在的对象,包括Page对象。Dispose能被重载。

总结
        以上就是ASP.NET页面生命周期中的十个事件。每次我们请求一个ASP.NET页面时,我们都经历着同样的过程:从初始化对象到销毁对象。通过了解ASP.NET页面的内部运行机制,我相信大家在编写、调试代码的时候会更加游刃有余的。