System.Web.UI.Page类提供了ASP.NET应用程序从aspx文件创建的所有对象的基本行为,该类派生自TemplateControl并实现了IHttpHandler接口。
TemplateControl是抽象类,为ASP.NET页面和用户控件提供了一组基本的功能。该类的上一层次为Control类,Control类定义了由ASP.NET服务器端元素(页面、控件和用户控件)共享的属性、方法和事件。
TemplateControl类实现了INamingContainer接口,因此,Page类还是其所有子控件的“命名容器”。控件的命名容器是实现INamingContainer接口的第一父控件。INamingContainer是不含任何方法的标志性接口,ASP.NET对实现该接口的页面或控件创建额外的命名空间,以对该页面或控件中的子控件进行命名。Page类是所有页面子控件的命名容器。
Page类的属性
Page对象的属性分为三类:内部对象、Worker属性、页面特有属性,下面分别介绍。
Page类的内部对象
Worker属性
在ASP.NET应用程序上下文中,Page对象是树将结构的根节点,因此,NamingContainer和Parent这样的属性总是返回null。此外,Page属性返回的是代表自身的实例(即C#中的this)。
上下文属性
Page对象的三个与ID有关的属性(ID、ClientID和UniqueID)总是返回空字符串,因为它仅用于服务器控件。
Page类的方法
用于呈现的方法
在ASP.NET页面中,runat属性为server的任何控件都不能放在<form>标签外。Web和HTML控件会通过VerifyRenderingInServerForm方法确保自身被正确呈现。在理论上,自定义控件在呈现时也应该调用该方法。但在很多情况下,自定义控件一般会内嵌或派生自能够自身做检查的Web或HTML控件。
Page类没有直接暴露ClientScriptManager类的GetWebResourceUrl方法,该方法提供了一个开发者们盼望已久的功能。在开发控件时,我们经常需要添加嵌入的静态资源(如图像或脚本文件)。一般可令这些文件单独下载,但这种方法不太优雅。VS2003及以上版本允许我们将资源嵌入到控件程序集中,但如何以编码方式将其获取并绑定到控件上呢?如,将一存储在程序集中的图像绑定到<img>标签上。GetWebResourceUrl方法就用于返回特定资源的URL。该URL指向一种新的资源服务(webresource.axd),该服务能从程序集中获取并返回被请求的资源。
示例:
img.ImageUrl = Page.GetWebResourceUrl(typeof(TheControl), gifName);
第一个参数Type对象用于对包含资源的程序集进行定位;第二个为嵌入资源的名称。返回的URL形式如下:
WebResource.axd?a=assembly&r=resourceName&t=timestamp
timestamp值为程序集的时间戳。它的作用是,如果程序集被修改,可使浏览器再次下载更新的资源。
控件相关的方法
在ASP.NET中,runat属性很关键,但实际上,其作用无非是对周围的标记文本做标注,并为解析和实例化提供参考,它不包含实例化控件所需的信息。
脚本相关的方法
列于上表的方法使我们能够向客户端页面添加JavaScript代码。在使用其中的方法时,我们实际上是通知当前页面对象,在页面被呈现时,插入那些脚本代码。因此,执行这些方法后,脚本相关的信息仅仅是缓存到一内部结构中,稍后在页面对象生成HTML文本时,才会用到那些信息。
Page类的事件
当某个页面被请求时,它的类及其所包含的服务器控件会负责处理请求,呈现HTML输出,并随后发回客户端。由于HTTP协议的固有特性,客户端与服务器间的通信是无状态且非连接的。而实际的应用程序需要状态,以便维护对同一页面的后续调用。ASP.NET提供了一种内建架构,能以透明的方式对页面状态进行存储和恢复。尽管基于无状态协议,但以这种方式,从客户端体验到的是连续的执行过程。
视图状态简介
这种连续性的表象,一方面与页面的设计和工作方式有关,另一方面是ASP.NET页面视图状态造成的。同时,服务器端控件也发挥着重要作用。在页面将其内容呈现为HTML之前,页面要将自身及其所含控件的状态信息存储在持久性介质(一般为隐含字段)中。当该页面回发后,其状态会从隐含字段中被反序列化,用于对声明在页面布局中的服务器控件实例进行初始化。
每个页面实例都有其特有的视图状态,因为该信息嵌入在HTML中。这样,控件会以上一次创建的视图状态(即该面最后一次被呈现发送到客户端时的状态)值进行初始化。此外,页面周期中还有一个阶段,将已存储的状态与由客户端做出的更新合并。在回发后,页面执行时,它会发现一个有状态的且更新过的上下文。
这里做了两个假设,第一个假设是,页面总是投递给自身,并携带着状态信息;第二个假设是,服务器端控件必须带有runat=server属性,以便在页面回发后具有“生命力”。
单窗体模型
ASP.NET页面只支持一个服务器端<form>(窗体)标签,所有要与服务器交互的控件,必须全部置于该窗体中。窗体和控件都必须带有runat属性,否则会被视为纯文本,并被逐字输出。在服务器端,窗体是HtmlForm类的实例。HtmlForm类没有暴露任何相当于HTML<form>标签的Action属性。其原因在于,ASP.NET页面总是投递给自己。
不包含服务器端窗体,及使用HTML窗体(不带runat属性的<form>标签)的页面,也是有效的ASP.NET页面。在ASP.NET页面中,HTML和服务器窗体可以同时存在。然而,只能有一个<form>标签的runat属性设置为server。HTML窗体会像一般窗体一样,使我们能够向程序中的任何页面投递。但这样的问题在于,状态信息不会被自动存储。换言之,仅当窗体使用一个服务器<form>元素时,ASP.NET Web窗体模型才会工作。
异步页面
ASP.NET页面会被HTTP处理程序作为Page类的实例处理。每个请求会占用ASP.NET线程池中的一个线程,在请求完毕后该线程才会被释放。倘若被请求的页面频繁启动外部的、高耗时的任务呢?问题在于,ASP.NET进程虽然闲置,但池中没有空闲的线程来处理新入的其他页面的请求。为减轻这个问题,ASP.NET支持异步处理程序(通过IHTTPAsyncHandler接口)。
异步ASP.NET页面的构建分两个步骤:定义@Page指令的Async属性为true及注册的若干异步执行的任务。异步任务可通过两种途径注册:为PreRenderComplete事件定义异步处理程序Begin/End或创建代表异步任务的PageAsyncTask对象。只要在PreRender事件被触发前定义就可以,一般放在Page_Load事件中。
Async属性
该属性为true时,页面解析器会在aspx资源的动态生成类中实现IHttpAsyncHandler接口,并且使页面能为PreRenderComplete事件注册异步处理程序。