开篇:上一篇我们了解了所谓的请求处理管道,在众多的事件中微软开放了19个重要的事件给我们,我们可以注入一些自定义的业务逻辑实现应用的个性化设计。本篇,我们来看看WebForm模式下的页面生命周期。
(1)Part 1:前奏
(2)Part 2:核心
(3)Part 3:管道
(4)Part 4:WebForm页面生命周期
(5)Part 5:MVC页面声命周期
在前面对于请求处理管道的介绍中,我们已经了解了一个ASP.NET WebForm页面请求事件的整体流程。那么,在其中一个最重要的部分就是ASP.NET Page页面,但是我们并没有对其进行详细讨论。因此,我们在此深入地了解一下ASP.NET页面事件。
每一个ASP.NET Page页都有2个部分:一个部分是在浏览器中进行显示的部分,它包含了HTML标签、viewstate形式的隐藏域 以及 在HTML input中的数据。当这个页面被提交到服务器时,这些HTML标签会被创建到ASP.NET控件,并且viewstate还会和表单数据绑定在一起。另一个部分是在xxx.cs文件中的进行业务逻辑操作的部分,一旦你在后置代码中得到所有的服务器控件,你可以执行和写入你自己的逻辑并呈现给客户浏览器。
其中,后台代码类是前台页面类的父类,前台页面类则是后台代码类的子类。这一点,可以通过查看每个aspx文件中的头部,我们都会看到以下的一句代码:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="FirstPage.aspx.cs" Inherits="WebFormDemo.FirstPage" %>
其中CodeBehind这个属性定义了此aspx页面的专属后台代码文件的名称,而Inherits这个属性则定义了此aspx页面所要继承的父类的名称(这也可以简单地说明,aspx页面会单独生成一个类,与后台代码类不重合在一起)。因此,aspx.cs就是aspx的后置处理代码,负责处理aspx中<%%>和runat="server"的内容。
现在这些HTML控件会作为ASP.NET控件存活在服务器上,ASP.NET会触发一系列的事件,我们也可以在这些事件中注入自定义逻辑代码。根据你想要执行什么样的任务/逻辑,我们需要将逻辑合理地放入这些事件之中。
TIP:大部分的开发者直接使用Page_Load来干所有的事情,但这并不是一个好的思路。因此,无论是填充控件、设置ViewState还是应用主题等所有发生在页面加载中的所有事情。因此,如果我们能够在合适的事件中放入逻辑,那么毫无疑问我们代码将会干净很多。
二、ASP.Net Page的页面事件流程
| 顺序 | 事件名称 | 控件初始化 | ViewState可用 | 表单数据可用 | 什么逻辑可以写在这里? |
| 1 | Init | No | No | No |
注意:你可以通过使用ASP.NET请求对象访问表单数据等,但不是通过服务器控件。 动态地创建控件,如果你一定要在运行时创建;任何初始化设置;母版页及其设置。在这部分中我们没有获得viewstate、提交的数据值及已经初始化的控件。 |
| 2 | Load View State | Not guaranteed | Yes | Not guaranteed | 你可以访问View State及任何同步逻辑,你希望viewstate被推到后台代码变量可以在这里完成。 |
| 3 | PostBackdata | Not guaranteed | Yes | Yes | 你可以访问表单数据。任何逻辑,你希望表单数据被推到后台代码变量可以在这里完成。 |
| 4 | Load | Yes | Yes | Yes | 在这里你可以放入任何你想操作控件的逻辑,如从数据库填充combox、对grid中的数据排序等。这个事件,我们可以访问所有控件、viewstate、他们发送过来的值。 |
| 5 | Validate | Yes | Yes | Yes | 如果你的页面有验证器或者你想为你的页面执行验证,那就在这里做吧。 |
| 6 | Event | Yes | Yes | Yes |
如果这是通过点击按钮或下拉列表的改变的一个回发,相关的事件将被触发。与事件相关的任何逻辑都可以在这里执行。 PS:这个事件想必很多使用WebForm的开发人员都很常用吧,是否记得那些Button1_Click(Object sender,EventArgs e)? |
| 7 | Pre-render | Yes | Yes | Yes | 如果你想对UI对象做最终的修改,如改变属性结构或属性值,在这些控件保存到ViewState之前。 |
| 8 | Save ViewState | Yes | Yes | Yes | 一旦对服务器控件的所有修改完成,将会保存控件数据到View State中。 |
| 9 | Render | Yes | Yes | Yes | 如果你想添加一些自定义HTML到输出,可以在这里完成。 |
| 10 | Unload | Yes | Yes | Yes | 任何你想做的清理工作都可以在这里执行。 |
三、反编译探秘ASP.Net Page页面生命周期
前面我们简单地了解了一下ASP.NET Page的页面事件,现在我们来通过Reflector反编译一下一个demo程序集,来感受一下ASP.NET Page的页面生命周期。
3.1 准备一个ASP.NET项目
(1)假如我们有以下的名为Index的一个aspx页面:
<html xmlns="http://www.w3.org/1999/xhtml"> <head id="headIndex" runat="server"> <title>Index页</title> </head> <body> <form id="formIndex" runat="server"> <div> 哈哈,我是ASP.Net WebForm,下面看我的表演。 <br /> <% for (int i = 0; i < 5; i++) { Response.Write("I am a webform page.<br/>"); } %> <br /> <%= GetServerTime() %> <br /> <asp:TextBox ID="txtDateTime" runat="server"></asp:TextBox> <asp:Button ID="btnGetTime" runat="server" Text="获取时间" onclick="btnGetTime_Click" /> <br /> <% GetDllInfo(); %> </div> </form> </body> </html>