2.2 ASP.NET AJAX架构总揽
Ajax应用程序将运行于客户端。作为一种Ajax的实现框架,ASP.NET AJAX应用程序也不例外。ASP.NET AJAX客户端组件将运行于浏览器中,提供管理界面元素、调用服务器端方法取得数据等功能。ASP.NET AJAX的服务器端控件则主要为开发者提供一种他们所熟悉的、与ASP.NET一致的服务器端编程模型。这些服务器控件将在运行时自动生成ASP.NET AJAX客户端组件,并同样发送至客户端浏览器执行。
由此可见,ASP.NET AJAX的架构依然可以分为服务器端和客户端两个部分。让我们从作为基础出现的服务器端功能开始。
2.2.1 服务器端架构
ASP.NET AJAX的服务器端架构如图2-1所示。

图2-1 ASP.NET AJAX服务器端架构
从图2-1可以看到,ASP.NET AJAX建立于ASP.NET框架之上,并对ASP.NET的几个重要部分均进行了修饰和封装,以方便ASP.NET AJAX客户端使用。ASP.NET AJAX服务器端架构分为如下几个部分。
(1) ASP.NET AJAX服务器端控件(ASP.NET AJAX Server Side Control):这部分控件用来提供实现ASP.NET AJAX功能的基础设施(例如生成客户端脚本引用的ScriptManager和ScriptManagerProxy控件),或者不依靠于其他ASP.NET控件来提供一些Ajax功能(例如实现页面局部更新的UpdatePanel控件)。AJAX Control Toolkit中也提供了一些这样的控件。这部分控件的使用方法和传统的ASP.NET服务器端控件完全一致,在Visual Studio中将其拖放到设计器界面中并加以配置即可正常工作。第3章和第10章将详细介绍这些控件。
(2) ASP.NET AJAX服务器端扩展器控件(ASP.NET AJAX Server Side Extender):这部分控件作为原有ASP.NET服务器端控件的扩展,旨在为这些控件提供某些客户端Ajax行为。例如AutoCompleteExtender可以为TextBox控件提供自动完成的功能;DragOverlayExtender可以为现有的大部分服务器端UI控件提供“悬浮”在页面上的功能,即可以用鼠标拖动到页面的任意位置。AJAX Control Toolkit中的大部分控件均是以这种服务器端控件扩展的形式提供的。这也是为现有ASP.NET应用程序添加Ajax功能的最好方法。第3、4、8、9章将详细介绍这些控件。
(3) ASP.NET AJAX服务器端远程Web Service桥(ASP.NET AJAX Web Service Bridge):由于安全限制,客户端JavaScript不能跨域名访问其他主机上的远程Web Service。ASP.NET AJAX为这种在其他服务器上的Web Service提供了一种自动的代理,即ASP.NET AJAX Web Service Bridge,并为其注册了一个新的文件扩展名.asbx(其中“b”即代表“bridge”)。一个asbx文件就是一个标准的XML文件,以声明的方式描述了某远程Web Service的信息,例如URL、方法名以及参数等。然后ASP.NET AJAX会自动将其编译成位于本服务器上的代理。这样,客户端脚本即可通过调用这个位于相同域名上的Web Service来访问其代理的其他域名上的真实的Web Service,以实现JavaScript跨域名的访问。由于ASP.NET AJAX服务器端对远程Web Service的代理与ASP.NET AJAX客户端开发联系非常紧密,所以这部分内容将放在本书第Ⅱ卷中详细介绍。
(4) ASP.NET 应用程序服务的客户端代理(ASP.NET Application Service Client Side Script Proxy):我们都知道,ASP.NET为常见的Web开发功能提供非常好的内建支持,包括用户身份认证、用户个性化、本地化等服务。ASP.NET还支持在页面的后置代码(Code Behind)中声明的公有方法,然后在页面(aspx或ascx文件)中直接对其进行调用。借助于ASP.NET,编写并发布Web Service也同样非常的简单。但是ASP.NET提供的这些功能均需要在服务器端才能使用,也就是说,一旦页面发送到了客户端,客户端就无法再直接使用这些强大的功能了。而ASP.NET AJAX框架则可以通过注册一些必要的HTTP Handler和HTTP Module来对这些服务器端功能进行包装,并自动生成这些服务的客户端JavaScript代理。这样就让客户端JavaScript也可以通过这些脚本代理来直接访问这些服务器端的功能。这部分内容同样与ASP.NET AJAX客户端开发有着紧密的联系,所以也将在本书的第Ⅱ卷中详细介绍。
综上所述,ASP.NET AJAX服务器端部分主要有两个功能:第一,发送给客户端其运行所必需的JavaScript脚本;第二,将ASP.NET提供的丰富的功能以JavaScript的形式暴露给客户端使用。
2.2.2 客户端架构
ASP.NET AJAX的客户端架构如图2-2所示。
在图2-2中可以看到,按照逻辑上对ASP.NET AJAX的客户端脚本库架构进行划分后,可将其分为如下几个部分。
(1) 浏览器兼容层:JavaScript和DOM的实现,在每个浏览器中都有一些轻微的差异,其中最明显的莫过于不同浏览器中对XMLHttpRequest对象的实现了。在第1章的Ajax示例程序中,想必你已经看到手动创建一个XMLHttpRequest对象是多么困难与麻烦。ASP.NET AJAX的浏览器兼容层是所有其他ASP.NET AJAX功能的基础,旨在抹平各个浏览器之间的差异,提供给其他各层统一的应用编程接口。开发者在编写运行于ASP.NET AJAX中的控件时,也无需再考虑浏览器之间的各种差异,只要使用了这一层所提供的API,那么其他的所有兼容性事宜都将由ASP.NET AJAX自动处理。

图2-2 ASP.NET AJAX客户端架构
(2) 核心功能实现层:该层旨在扩展客户端JavaScript的功能,例如为JavaScript引入类、接口、继承、命名空间、事件处理、数据类型等特性。这样就让JavaScript变成了一个完全面向对象的语言,开发者可以充分利用面向对象的各种成熟的设计方法,编写出高质量、可重用的组件和代码。
(3) 框架基础类库:基于核心功能实现层所提供的面向对象功能,这一层实现了一些非常有用的ASP.NET AJAX框架基础类库,包括StringBuilder、Timer、Debugger、Trace等。这些对基础功能的封装在本层以上的各层中都被广泛地使用。
(4) 网络访问层:在第1章的示例程序中你可能已经发现,使用XMLHttpRequest对象进行异步服务器调用的代码还远远称不上“简洁易懂”。开发者需要掌握XMLHttpRequest对象的各个方法和属性,同时也要对HTTP有较深入的了解,并不得不按照固定的模式重复这个代码结构。ASP.NET AJAX客户端框架所提供的这一层将操作XMLHttpRequest对象的复杂性封装起来,并为上层以及开发者提供一个简单明了的应用编程接口,只要书写几行代码即可完成从前需要数十行代码才能完成的功能。网络访问层同样还包括了服务器端发送来的ASP.NET AJAX客户端代理的代码。这样,上层通过调用这些ASP.NET AJAX客户端代理,即可访问到服务器端的相应资源,例如用户身份认证、用户个性化信息和服务器端Web Service等。
(5) 用户界面基础类库:这一层提供ASP.NET AJAX界面控件的基础设施,包括行为(behavior)、动作(action)等,还有最重要的绑定机制。ASP.NET AJAX中的绑定比传统意义中的“数据绑定”要强大得多,它可以将各种客户端控件/组件连接到一起,让数据乃至对象自动地在绑定双方控件/组件中双向地传递,在传递的过程中还可以使用转换器(transformer)对数据进行转换。绑定也正是ASP.NET AJAX客户端脚本所使用的面向组件编程的实现基础。
(6) ASP.NET AJAX XML脚本引擎:ASP.NET AJAX XML脚本是一种基于XML的、新型的编程方式,在本书第Ⅱ卷中将对其语法进行详细介绍。使用ASP.NET AJAX XML脚本,开发者只需要用书写XML的方式定义页面中所需要的控件/组件,并通过用户界面基础类库所提供的绑定机制将各个控件/组件彼此连接起来,就可以用更少的代码编写出功能强大的应用程序。ASP.NET AJAX XML脚本引擎将在ASP.NET AJAX客户端框架初始化完成之后解析这一段基于XML的声明,然后将其转换为实际的JavaScript控件/组件,并对其应用各种行为、绑定等,进而初始化整个ASP.NET AJAX客户端应用程序。
(7) ASP.NET AJAX客户端控件/组件:这部分中包含了大量类似ASP.NET服务器端控件一样良好封装、模块化的客户端控件/组件,例如表示简单界面元素的TextBox、表示复杂绑定列表的ListView、验证用户输入的Validator、位于客户端的离线数据源DataSource、实现动画效果的Animation、提供鼠标拖放支持的DragDropList等。开发者只需要创建一个控件/组件对象,就可以面向对象的方式使用它们封装好的强大功能。同时,作为控件开发者,也可以很方便地通过继承等面向对象方式来对现有的控件/组件进行扩展。
上述这部分内容均将在第Ⅱ卷中介绍。除此之外,图2-2中还可以看到ASP.NET AJAX支持编程式语法和声明式语法两种不同的客户端编程语法模型。
编程式语法:即传统的编程方式,手工为某个对象编写事件处理函数,并在该处理函数中对该对象或另外的对象进行操作。例如,下面的代码将在用户点击按钮时设定文本框中的文字为“Hello”:(目前我们可能还不了解这段代码中每一句的具体意义,但这并不妨碍对代码结构的理解。在第Ⅱ卷中,将详细介绍这些语句的含义。)
var g_tbInfo = null;
var g_btn = null;
function pageLoad()
{
g_tbInfo = new Sys.Preview.UI.TextBox($get('tbInfo'));
g_tbInfo.initialize();
g_btn = new Sys.Preview.UI.Button($get('btn'));
g_btn.add_click(btn_clicked);
g_btn.initialize();
}
function btn_clicked()
{
g_tbInfo.set_text('Hello');
}
可以看到,这段代码中首先定义了两个全局变量,分别表示页面中的文本框和按钮。然后在pageLoad()函数(初始化函数)中对文本框和按钮进行初始化,并将按钮的click事件处理函数设置为btn_clicked()。最后,在btn_clicked()事件处理函数中,将文本框中的文字设置为Hello。
声明式语法:ASP.NET AJAX引入的ASP.NET AJAX XML脚本即采用了这种编程语法模型。使用这种方法,开发者将以XML声明的方式来定义程序中的控件/组件,并定义这些组件各自的行为以及相互之间交互的方式。这样就“强迫”开发者使用纯粹面向组件的开发方式,既增强了代码的可重用性,也使代码更加易于理解。下面的声明式语法代码与前面编程式语法中那个例子的功能完全一致:
<textBox id="tbInfo" />
<button id="btn">
<click>
<setPropertyAction target="tbInfo" property="text" value="Hello" />
</click>
</button>
如果你仔细阅读过上述代码,那么似乎也不用再多说明了。这段代码的自解释能力非常强:首先使用<textBox>和<button>标签定义了两个控件;然后用<button>中的<click>子标签表示该按钮的click事件,<click>标签中的<setPropertyAction>子标签表示处理该事件的方法为“设定某个对象的某个属性”。在这里我们将文本框的text属性值设定为Hello。就这么简单!
比较上述两段实现同样功能的代码,相信你已经清楚地分出其中的优劣了。但如果你从前并没有接触过这种声明式语法,那么也许很难能够立刻接受。不过没有关系,通过本书的第Ⅱ卷中的详细介绍,相信你将渐渐地熟悉这种强大的编程模型,也一定会迅速地喜欢上它。







