技术开发 频道

剖析ASP.NET 2.0代码模型

【IT168 技术文档】
一、 引言
 ASP.NET 2.0内容博大精深,许多方面都值得我们重新“审视”。在web表单开发方面,ASP.NET 2.0继续沿用1.x版本中的code-behind和单文件模型;然而,具体使用哪一种模型倒是一个十分困难的选择。
典型的web表单一般都包含各种控件(例如,标签、按钮和数据网格)及编程逻辑。在ASP.NET 2.0中,共存在两个途径来管理这些控件和代码片断:单文件页面模型;code-behind页面模型。无论选择哪种模型,真正理解运行时刻库在后台处理和执行你的web表单的方式才是最重要的。
在本文中,我们将集中探讨ASP.NET 2.0 web表单在设计时刻与运行时刻的运行规律。
二、 code-behind模型
当你把一个新的web表单添加到一个工程并从对话框中选择“Place code in separate file”复选框时,Visual Studio 2005会使用code-behind模型创建一个web表单。相应地,Visual Studio把两个文件添加到当前工程:一个aspx文件和一个.cs(或.vb)文件。如果我们在创建一个Default.aspx web页面,那么这个aspx文件看起来如下所示:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server"> <div> </div> </form> </body> </html>

 该ASPX页面包含了一个表单中的典型标记:html,head和body标签等。我们使用设计器添加到该表单的任何控件都将出现在这个ASPX文件内。这里的重点是顶部的@Page指令。其中,AutoEventWireup属性默认为true(稍后我们再讨论)。CodeFile属性链接到源代码文件(相应于这个表单的编程逻辑),在此是Default.aspx.cs。运行时刻会使用CodeFile属性来决定它使用哪个源代码文件来编译这个ASPX页面。同样,Inherits属性告诉运行时刻将用作这个web表单的基类的名字。现在,先让我们来分析该ASPX页面的code-behind文件。

using System; using System.Web.UI; public partial class _Default : System.Web.UI.Page{ protected void Page_Load(object sender, EventArgs e) { } }

在此,我们看到了_Default类,还有标准的Page_Load事件处理器。典型情况下,我们使用Page_Load事件处理器初始化控件并实现数据绑定。注意,目前,在VB.NET中,缺省的.vb文件中还不包含这个Page_Load事件处理器,但是,你能够容易地从文本编辑器上部的页面事件下拉列表中添加该事件处理器。无论选用哪一种语言,关键还在于“partial”关键字。
这个“partial”关键字是.NET 2.0新引入的,既可用于C#也可用于VB.NET中,并且含义相同。partial允许我们把一个类的定义放置于两个或多个源代码文件中。而这在以前的.NET框架版本是根本不可能的:一个类定义必须存在于单个.cs或.vb文件中。
该partial关键字承担着一个重要的角色,因为它允许运行时刻使用其它成员来扩展我们的_Default类的定义。例如,任何以ASPX标记runat=”server”和一个id属性出现的控件都将最终在行为上类似于我们的类中的一个成员变量。例如,在Page_Load事件处理器中,我们已经能够存取一个名字为form1的变量。那么,这究竟是如何发生的呢?下面让我们来详细地分析当我们浏览这个web应用程序并执行该表单时发生了什么。
三、 code-behind模型中的编译问题
 当一个相应于web表单的浏览器请求到来时,ASP.NET运行时刻需要完成两个任务。首先,运行时刻需要分析并理解我们已经放到ASPX文件中的那些控件。该分析过程包括读取表单的ASPX部分,并且生成创建那些控件和HTML标记的源代码。第二个任务是,编译生成的源代码。注意,通过进入.NET 2.0框架安装目录下的“Temporary ASP.NET Files”子目录(在我的机器上是“C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files”),我们可以实际观察一下运行时刻生成的代码。下列是通过分析前面的ASPX文件生成的代码文件的一个摘要。从该片断中,我们可以清楚地看到运行时刻是如何在后台把上面的内容统一到一起的。

public partial class _Default : System.Web.SessionState.IRequiresSessionState { protected System.Web.UI.HtmlControls.HtmlForm form1; protected System.Web.Profile.DefaultProfile Profile { get { return ((System.Web.Profile.DefaultProfile)(this.Context.Profile)); } } protected System.Web.HttpApplication ApplicationInstance { get { return ((System.Web.HttpApplication)(this.Context.ApplicationInstance)); } } } namespace ASP { public class Default_aspx : _Default { public Default_aspx(){ // ... } protected override void FrameworkInitialize(){ base.FrameworkInitialize(); this.__BuildControlTree(this); this.AddWrappedFileDependencies(ASP.Default_aspx.__fileDependencies); this.Request.ValidateInput(); } // ... } }

 在此,首先要注意的是,在代码最开始的partial类定义。这个partial类通过添加一些其它成员来负责最终完成在code behind文件Default.aspx.cs中的_Default类的定义。这些成员中有一个字段就是用来描述页面上的HTML form标签(它同样也有一个runat=”server”标记)。我们放到该表单的任何其它服务器控件都会成为该类有成员。
在这个生成文件中的第二个类(Default_aspx)描述了这个ASPX页面本身。这个类继承自_Default类并且包含所有的用于初始化表单、实例化服务器控件的代码。
运行时刻将把这两个类(_Default和_Default_aspx)编译到同一个程序集中。这个程序集位于临时ASP.NET文件目录下。
最后一个需要我们回答的问题是:如何调用Page_Load方法?如果你分析一下在该code-behind和生成文件中的所有代码,那么,你会发现在其中的C#代码中并没有使用代理。
秘密在于在前面讨论过的Default.aspx内@Page指令中的AutoEventWireup属性。这个AutoEventWireup属性被设置为true(在没有显式使用时缺省也为true)。当为true时,ASP.NET运行时刻试图基于方法名称把页面方法依附到事件上。如果方法遵循命名约定Page_EventName,那么这个方法将对应一个名为EventName的事件。例如,运行时刻将把Page_Load方法绑定到加载(Load)事件,而把Page_Init方法绑定到Init事件。注意,所有这些发生时根本不存在显式的代理语句。


0
相关文章