在这里我将试图考察一下目前.NET平台的下的Ajax框架,我也试图从中总结出来一种方法,使得你可以在众多基于.NET平台的Ajax框架和工具包中找到你所合适的一种,同时也希望你在考察、预研和使用这些流行的这些Ajax-NET 的框架时,做得理性和有的放矢。
我想,文章的方法会给目前使用Ajax的.NET用户带来帮助,从而提高你在.NET平台下使用Ajax的体验。为什么这么说,因为最近我的一个客户(应该是一些客户)的研发主管对我说,我们对Atlas 非常兴趣,想了解更多一些相关的内容和如何开始看待Atlas,因为下个月会来一个Atlas的专家和我们交流。因为我知道这个主管手上掌握着一个Ajax架构的业务应用,目前在考虑从.NET v1.1迁移到.NET v2.0,Atlas能在怎样的程度上帮忙他或他的Team?我没有说太多,因为心里我有些吃惊,目前的他们的架构应用Atlas 可能并不是一个明智的选择,当然这个担心基于我目前对Atlas的理解。
我列举和讨论的Ajax-NET的框架和工具包括Atlas(Jan CTP), Anthem.NET, MagicAjax.NET , Ajax.NET Professional 和wwHoverPanel Control,这基本都是我关注的.NET平台的下的Ajax 的一些框架和实现。 基本上也都是我的这篇文章中列举的,另外一个原因是因为他们基本上都是开源的,这个非常重要,因为没有源代码,我们将不知道究竟发生了什么。另外我无意于使之成为像Daniel Zeiss作的这个比较报告。
首先,开门见山的说明我的观点。
对于开源或现有的Ajax-NET技术或框架的选用必须针对你目前应用的架构来选取和考虑,如果你目前的架构是"似Ajax"的,那么你在选择现在所有流行的Ajax-NET的技术的时候都必须非常小心;而如果你目前的应用是使用传统的ASP.NET的应用架构(或准备用ASP.NET v2.0开始创建新的应用),那么目前流行的Ajax-NET的框架和技术都是普遍适合的,关键你要在合适的时机选择合适的某个框架或实现。
在我的眼中,目前流行的Ajax-NET的框架或实现都是Add-in (Plug-in)的模式的,也就是说这些框架对于所有后一种即使用传统的ASP.NET的应用架构(或准备用ASP.NET v2.0开始创建新的应用)是Awared的也就是非常有利和方便的。但对于"似Ajax"的架构来说,情况有所不同,需要你从另外的角度来衡量,有选择的使用。
那什么是"似Ajax" 的架构呢,这就是说,你的应用程序是在Ajax概念提出之前就创建的。从客户端和服务器端的交互分析来说,你的客户端有大量的Javascript 代码接受XML数据,进行对象的序列化,然后使用Javascript配合其它的HTML技术展现这些对象和数据,也可能你还有一堆HTC或其它的Javascript的HTML表现层控件。你的服务器端是一个Facade(或者是Adapter,Observer)模式的(Handler)控制器,接收客户端Javascript的XML请求数据后,然后解析XML,然后调用相应的某个服务或业务组件,再将结果以XML的形式返回给客户端Javascript ,客户端的Javascript接收之后,再进行处理和显示,因为可以使用HTML的DOM 和CSS,所有页面的展现是动态的。
这样客户端是Ajax in Action中描述的Script-centric architecture 或Data-centric interactions 的方式。而且这种方式和Jesse James Garrett列举的Ajax 是最类似的,只不过那时你或我不知道这个可以叫Ajax,只不过是现在的人误解了Ajax,Ajax成了一种技术,一种特性,而首先不是一种某种架构下Web 应用了。
而且目前流行的Ajax-NET的框架基本上都没有实现双向序列化,因为实现一个TextBox的自动完成客户端只用接收数据就行了,根本不用传回数据/对象到服务器端,同样做一个Ajax的状态进度条也不用,但这些都是Ajax啊,我们衡量的标准是异步的、页面没有刷新。
很抱歉,我用了这么字才解释完我的观点。最后可以这么说,如果你的应用已经是Ajax架构的,那么你需要仔细选择使用目前的Ajax-NET框架,确保它也提供双向序列化功能,兼容你原来的应用和架构。如果你的应用不是Ajax架构的,那么你可以依据一些条件来选择Ajax-NET框架。
然后我们回到文章的开始,来看一些流行的Ajax-NET框架
1. MagicAjax.NET
这是目前框架中版本号最小的一个Ajax-NET实现,许多人很喜欢它,甚至一见如故,但真的看过它的代码之后,我有些担忧。
MagicAjax.NET基于这样一种策略,即__doPostBack 会提及整个的ASP.NET页面,这样会导致页面刷新,所以MagicAjax.NET使用AJAXCbo.DoPostCallBack 做局部的提交,而每个AjaxPanel 中的内容则对应客户端即时的HTML内容,因为在MagicAjax.NET中,客户端只用执行eval(responseText) 服务器端Rendered返回的HTML就可以了(很被动)。
由于DoPostCallBack 会提交ViewState 以及AjaxPanelx$RBS_Store,几乎是用XMLHttpRequest 模拟一个正常的提交,所以服务器端可以创建页面的实例也可以根据ViewState 恢复所有的控件状态,同样AjaxPanel 以及AjaxControl 也都会实例化,然后接收客户端传来的_EventTarget, _EventArgument 走正常的ASP.NET控件的处理过程,等控件Rendered之后,最终的HTML输出被传回客户端,然后被客户端的eval 显示出来。
整个过程非常巧妙,这几乎是ASP.NET __doPostBack 的"Hook ASP.NET"版和加强版本。而HttpModel 主要是为了解决Session和交叉提交,进行客户端Javascript的整理和注入,当然也是这里接收客户端的请求,在Application_EndRequest中返回结果。剩下的代码都是处理控件在VS Web Design中的设计时支持。AjaxCallObject.js 和WebParts.js 每次都要传到客户端。
MagicAjax.NET 的一些不足和想法:
1、__doPostBack 的加强版,适合于ASP.NET的高级用户使用
2、由于和ASP.NET的页面处理机制依赖非常密切,控件的默认动作发生变化则可能不工作,比如第三方的某个自定义控件;
3、依赖ViewState ,如果是加密的ViewState,则可能工作不正常,我没有试,在代码中好像没有看见__VIEWSTATEENCRYPTED
4、是对ASP.NET 全部页面提交的优化,实现有限的Ajax功能,可扩展性不大
如果是基于ASP.NET 提供的控件和开发,那么MagicAjax.NET 是非常有效的,很好的解决了Session和跨页面状态的问题。而且客户端的操作和工作基本可以忽略,MagicAjax.NET设计贴近最近的ASP.NET的版本,目前不提供调用客户端直接调用页面的方法。但随着其发展,优势可能渐少,因为Atlas 最新的版本提供类似的UpdatePanel 控件。
2. Anthem.NET
目前是1.0版本,其设计理念是通过另外一个思路,遵循这样的理念--既然ASP.NET的各个标准控件没有实现提交功能,那么我可以产生一个提交的接口,然后继承原来的标准控件,然后再实现这个接口,这样每个控件都可以向服务器端单独进行提交。
每个控件的发生过程类似MagicAjax.NET,Anthem.NET提供了各个控件Javascript端的提交函数-这等于也截取了__doPostBack,之后Anthem.NET 还提供了完善的客户端的事件比如PostCallBack 和PreCallBack 这样的客户端事件,之后也将使用XMLHttpRequest 模拟一个传统的页面提交请求到服务器端,服务器端生成页面实例,这个过程和MagicAjax.NET一样,最后是将Rendered的HTML在控件的Render() 事件传回到客户端,客户端控件的innerHTML被赋值,动态更新。
和MagicAjax.NET不同的是,Anthem.NET没有容器的概念,因为每个控件都增加了提交接口,所以可以单独的提交,所以单位是以一个控件为单位进行一次提交,Anthem.NET的花费更小些(但服务器端是类似的,因为整个ASP.NET页面的Pipeline都会进行)。
此外,Anthem.NET 还有另外的功能,就是可以通过客户端调用页面中的方法并获得结果/数据,这种情况下,你将调用Anthem_InvokePageMethod 方法,而不是Anthem.NET提供的默认各个控件的提交方法。这样Javascript的回调处理函数中的result.value 将可以获得调用的服务端的某个方法(该方法以[Anthem.Method]为标记)的执行结果,因为JavascriptPost的数据中有Page/MasterPage/Control 了,那么服务器端很容易通过这个标识获得方法的地址,应用反射寻找[Anthem.Method]标记,然后调用,将结果返回到客户端。
Anthem.NET支持返回对象,DataSet,DataTable和 WriteDataRow(WriteDataSet,WriteDataTable,WriteDataRow,WriteObject),返回的是符合是JSON规范的字符串,这样客户端的Javascript就可以使用这些对象了。不同于MagicAjax.NET,Anthem.NET 没有使用HTTP Model,所以结果是在页面的PreRender() 事件中处理和返回请求的结果。
2.1 Ajax.NET Professional
我没有看过Ajax.NET Professional 的源代码,但从例子中看得其支持调用页面的某个方法,以及返回对象,DataSet,DataTable的数据,我认为Ajax.NET Professional 的实现和Anthem.NET 原理是一样的,虽然Ajax.NET Professional 使用了HTTP Model,这个只是和Anthem.NET 一样,最终处理结果的返回处理上稍有不同不同。比较起来,Ajax.NET Professional 没有重新继承所有常用的ASP.NET控件实现部分提交的功能,所以可能Ajax.NET Professional 比较强项的是调用页面上的某个方法,并在客户端获得结果的数据,这个已经够实现大部分的Ajax的功能了。
从这个层面上看,我认为Ajax.NET Professional 是相对笨重和复杂了。Anthem.NET不使用HTTP Model,提供控件基本的局部提交,也提供数据层面的客户端方法调用。Ajax.NET Professional 的源代码似乎总是不想共享 ,这也是我不喜欢它的另外一个原因。
无论如何,大家都没有提供两路的数据交换,即客户端可以获得服务器端的方法并获得结果和数据,但是目前都支持将这些对象/数据修改之后返回给服务器端。
Anthem.NET 的一些不足和想法:
1) Anthem.NET 也是一种"Hook ASP.NET"原理,旨在弥补ASP.NET的整页面的提交和PostBack,并且在客户端的数据访问和交互上做了加强。
2) Anthem.NET需要重新将ASP.NET提供的控件进行继承和包装,所以使用和功能的兼容性上非常敏感。
3) 也许微软下个版本的ASP.NET的标准控件可以借鉴Anthem.NET的做法,给各个控件增加这个远程回调的接口。
4) 目前版本的功能已经非常强大和略有些复杂了,而且部署比较方便,无需设置HTTP Model。
3. wwHoverPanel AJAX Control for ASP.NET
wwHoverPanel AJAX Control for ASP.NET 这也是一个ASP.NET的控件,但是提供了客户端回调(高级回调)、客户端调用页面方法,以及双向两路的序列化功能。
wwHoverPanel 吸取了MagicAjax.NET 和 Anthem.NET的优点,同时又结合了ASP.NET的客户端回调功能,是一个轻量级的Ajax组件。
看待wwHoverPanel 最大的两个特性中的一个是用很简单的方式实现了一个HoverPanel Behavior,这个实现比目前Atalas的Behavior 要简单,作者Rick Strahl 也强调这个主要是结合他具体的应用,比如这里提供了一个小的HTML板,可以显示获得的结果信息。
wwHoverPanel 也提供一个局部回调的方法,但是这点的实现上和MagicAjax.NET 以及 Anthem.NET完全不同,它是使用一个StartCallback的Javascript来组合查询字符串提交并且使用XMLHTTP发请求到服务器的某个页面(由ServerUrl 属性指定),之后这个页面将结果以Response.Write()的原生HTML内容返回。这个和ASP.NET的回调方法非常类似,而且还支持将请求发到本页之外的ASP.NET并获得结果,所以它增强了原来ASP.NET的客户端回调的方法,即支持其它页面的回调。可以说,这是一种基于URL的客户端回调。
wwHoverPanel 提供的第二个功能是,客户端可以调用服务器端中的某个页面的方法(这些方法以[CallbackMethod]进行标识),这种情况下,你要设置EventHandlerMode="CallPageMethod" ,然后使用wwHoverPanel.服务器方法名(参数,参数,...,回调处理函数)的方式进行调用。这个其实使用的是一个Javascript的CallMethod 方法,调用服务器端的请求。Javascript 的HandleCallback 则用来处理返回的结果,逻辑相对简单,尽管控件的innerHTML 也被赋值,但这个主要是为了维护作为客户端回调结果显示的小的HTML板的内容,否则就是调用页面中的方法了,那么结果就直接给客户端的回调方法了。
特色三,就是我说的双路的序列化功能了,其实这个场景我们也非常需要,比如我们用客户端回调或XMLHTTP请求获得了一个定单对象,那么客户端修改之后,我还想把它作为一个客户端调用的输入参数,返回到服务器端。这时候两路双向的序列化就需要了,因为这次服务器需要将Javascript的函数传了的数据序列化成.NET的类。这也就是JSON的双向序列化了(主要代码在JSONSerializer.cs ),这也是我挺喜欢的一个功能,因为我对这个功能关注很久,但是目前流行的Ajax-NET的框架都不支持这个功能。
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/webkaifa/)目前在wwHoverPanel 的场景中,我认为这是一种轻量级的实现,对于多层嵌套多组引用的对象图类型或是大规模容量访问压力下,客户端和服务器端都还需要优化,所以如果其作为Ajax架构,客户端和服务器端通信和传递数据的通讯层上,显然是有些单薄了。
wwHoverPanel 的一些不足和想法:
1) 该控件是目前我见过.NET平台下,惟一同时支持客户端回调和页面方法调用的Ajax 控件,同时又支持两路双向的序列化。
2) 相对来说,wwHoverPanel是设计最简单的一个,而且是基于控件不依赖HTTP Model和ASP.NET Page Pipeline,也不依赖ViewState
3) 该控件能够让你在Ajax特性实现的技术层面上,能够在客户回调和客户端调用页面方法两者中取得平衡。
4) 目前的客户端回调支持其它页面的回调,但是其结果输出需要输出原始的HTML,这个影响应用的分层和设计。
5) JSON的双向序列化是一个不错的方案,但高性能的场景下,应该考虑实现更高效的序列化框架
4. Atlas
这个产品,我就不列举具体的功能了,而主要说一下我对其的看法和持有的态度。因为在我的Ajax书评中提到过问题。
Atlas 是一个个性鲜明的产品,其优点是明显的,缺点也是明显的,但首先你必须认识到它还是一个比较复杂,拥有较高学习曲线的解决方案。对于其复杂性,老实说目前,大多数人还缺乏真实的感受。
最近的一个个版本-Jan CTP,我们看到了一些特性,其强大之处在于:
1.客户端(Javascript)的数据绑定、校验带来便利。
2. 新的Update Panels不仅拥有了MagicAjax.NET 的特性,而且功能更强,是目前Atlas中异步回调的主要控件。
3.内置了一些具体Ajax特性的控件,比如AutoCompleteExtender ,DragOverlayExtender
4. 提供了一些使用的控件比如,ScriptManager, Triggers ,TimerControl
5. 主要用途着重在提供一个客户端控件和服务器端控件的特性集成的方案和容易使用的开发效率上。
但缺点也是明显的,比如:
1. 客户端的Behaviors还很弱,模板(Templates)和UI增强(UI Enhancements)功能还没有看到。
2. 所谓的客户端Atlas控件(“Atlas” Client Controls)和服务器端的Atlas控件(“Atlas” Server Controls) 还没有一个明确的规范,所以现在你基本上还不能创建自定义的Atlas控件(无论客户端还是服务器端的)。
3. 目前还只支持调用Web Services的服务,对于ASP.NET的内置的服务以及WCF的服务支持也没有看见,也不支持页面或控件内的方法调用
4. 功能上还不稳定,一些功能仅是在特定条件下的特性实现,还不能满足部署生产环境的要求。我认为,如果Atlas发布Go-Live License,那么可以考虑Atlas的放入到正式的项目或应用中。
我并不建议,你现在就将它应用在一个老的ASP.NET 项目中,或是老项目迁移到ASP.NET v2.0时优先考虑它;更多时候,如果你是创建一个新的ASP.NET应用,而又跨越了其学习曲线的情况下,可以考虑使用它。目前的情况下,对于Atlas,我建议,你应该保持足够的关注和实践学习,但是要抑制住将其应用到项目中的兴趣;因为Ajax,你现在可以开始关注和学习它,但是你不能因为要实现Ajax一个特性,而立即选择Atlas,那么是可能有风险的。
注: Atals 的Microsoft.Web.Script.Serialization 命名空间中有JavaScriptObjectDeserializer和JavaScriptObjectSerializer两个对象,第一,我不确定其是否也是JSON 序列化,而且我也不确定目前是否支持两路双向的序列化;第二,目前的版本,我还不能进行自定义或扩展,同时也很难对于其性能做任何的结论。
基于Ajax 架构的Web应用框架
之前我提到过"似Ajax" 的架构,现在我要说的Ajax框架也就是指专门针对这种Ajax架构而提供的框架。目前,我还没有听说过特别好的这个领域的流行框架。但我知道我的身边,.NET领域,J2EE领域或PHP平台上都有这样的框架和应用,我认为,正是因为有很多这样应用,所以Ajax才会像某个模式一样,被撰有一个专门的名词。不过我感觉Ajax 渐渐变成了Ajax feature的代名词,变成了XMLHTTP的代名词,成了异步通讯,不刷新页面的技术表示法。直到我看过Ajax in Action这本书,我才把Ajax和系统的架构、设计模式,分布式对象的序列化和我之前的项目和经历联系在一切。
我修改了一些Jesse的图,来说明我认为的基于Ajax的架构是什么样的。
这也就是我上面说的“似Ajax”架构,首先它是一个Web应用;它的表现层用DHTML+CSS + HTC控件+ Javascript ,服务器端用.NET或任何的服务器端技术,中间以XML方式序列化和反序列化进行传递数据。
简单的说,客户端需要将请求的数据封装成一个XML数据通过HTTP传递给服务器端,服务器端处理这个请求,并将结果也以XML的形式返回到客户端,客户端再处理这些请求,然后使用HTML+CSS进行展示。其实如果不是Web客户端(浏览器)的问题,这是最简单的架构,但关键问题在于上面我们说的Javascript端的对象封装成一个XML,以及到服务端解析XML变成服务器端对象,然后再将结果封装成XML,传回给客户端(Javascript),客户端也解析XML数据,然后变成Javascript 中的对象的这个序列化和反序列化的问题。另外一个问题就是表现层的展现问题,怎么展现,用什么控件?
所以,一个Ajax架构的Web应用程序,必须解决下面的问题:
1. 双向两路的序列化问题
2. 表现层展现的问题
3. 传输时客户端和服务器端的数据安全问题
4. 性能问题
5. 国际化支持
最好玩的双向两路的序列化问题,最早接触的是JSON ,它的问题在于扩展性,数据类型的支持和性能,但是平台无关性比较好,什么浏览器都可以,因为它不需要用msxml2.DOMDocumen分析XML,本质上就是用字符串描述对象;之后多平台的应用的迁移经历中(比如CORBAR,J2EE的后台应用),开始接触到XML-RPC ,ICE,Hessian,Web Services等等。其中XML-RPC有Javascript 的支持库,Web Services也有Javascript的支持库,也就是你可以使用Javascript访问或者获得XML-RPC/Web Services的对象,但是如果你将其作为一个主要的通讯协议,那么就会遇到另外一些问题,比如性能、国际化的问题,又会困扰你,XML-RPC和Web Services的一个主要问题都是性能,因为他们传输的XML大小都太大了,但显然用这些实现一个Ajax的特性,那是完全没有问题了。
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/webkaifa/)比如,Atlas目前不也是使用一个Javascript库调用Web Services吗?,所以,你也可以这么做,同样你也可以用XML-RPC.NET 很快就可以实现一个Service,然后使用Scotandrew的XML-RPC javascript 库就可以在Javascript中发一个XML-RPC 消息请求这个服务,然后异步的获得这个结果,然后展现它。所以从技术的实现上讲,Ajax的特性非常容易实现,但从架构上来看。你需要思考更多的因素。当然直到最后,我们才发现,在项目中,最完美的方案是你自己写一个双向两路的序列化引擎供你的Javascript客户端使用。
这就说到了第二个问题,界面表现的问题,这个问题也是一个大的问题。这个问题一直会永远存在,Ajax之前没有人会太注意这些,但今天不同了,我想未来还会有很大的一个飞跃, Yahoo! 不是最近也开源了他的Yahoo! Web UI库,Atlas 也表示要提供更多的前端UI控件。无论如何,这个问题是,你的团队或组织是否有一套经过项目或客户检验的前端Javascript的库。无论是自己用Javascript写的也好,是自己写的一套HTC的控件库也好,总之这些是Ajax 架构中非常重要的一环。
Atlas 带来了另外一个思考问题,就是服务器端控件可能可以通过某种方式和Javascript的控件很好的集成在一起,以前我们用HTC解决了重用、性能、Behaviors、甚至模板功能。但是新的特性还是有比如数据的绑定、缓存和校验、甚至是数据编码和压缩、加密和解密,Javascript UI前端还是有许多可以做的,而且如何无缝的集成两者,这个有非常大的意义。
接着安全、性能、国际化等等,架构中的问题需要你依次考虑和解决,如果这么看Ajax,我认为,目前的Ajax框架还有很长很长一段路要走,同样真正完美支持Ajax架构的还需要继续努力。这些也是我在这篇专栏文章中的观点。
把这些合在一起,那么Ajax架构的开发包或框架,就应该是包含了上述几个问题(两路双向的序列化、Javascript UI 表现库、安全、国际化和性能等等)解决方案的一个平台实现。
同样也许你会说,不就是Ajax吗? 我干嘛要搞这么复杂,一定要搞到架构这个层面。
我认为,
第一,从架构的层面看Ajax,然后再应用相关的技术,比你直接使用某个Ajax框架然后再理解Ajax,你会从这个过程中收获更多。
第二,对于一个开发团队/组织来说,真正Ajax架构的产品,可以带来效益和具体的生产力。比如,我身边就有拥有这样的优势的团队,他们拥有一套统一的由Javascript+HTML+CSS+HTC的前端表现层,而后台的业务系统有两个平台,一个.NET平台和J2EE平台;同样我身边的也有这样的团队,他们拥有一套统一的由Javascript+DHTML+CSS+HTC+VML+ASP.NET的前端表现层,但他们的后台业务层分别来自.NET平台、J2EE平台和Unix平台,我不能说Ajax架构的应用似乎就是统一Web 表现层。因为从今天看到他们的明天,也许会是, 一个ASP.NET V2+Atlas 的统一表现层,一个统一CAB+Smart Client 的统一表现层,也可以是一个WPF 3D的统一表现层,也可以是一个Xgl 桌面的统一层......
第三,从这架构的层面上,你也能够非常容易理解SOA或ESB概念,和SOA相比,Ajax架构的区别在于,Ajax有足够的松散耦合,但它依然以应用的数据为中心,更多的是一个面向Messages的架构,而且对于流行的WS-*协议的支持非常有限。
但是假如,今天你或你的团队已经有了一个Ajax 架构的应用,那么你是不是应该要小心选择现有的Ajax框架,因为这些Ajax的特性,相对于目前的架构来说,是多么小,但又可能会产生很大危害的一个因素。也许这样的团队并不多,也许也很多,但是只有我们从更高更深的层次来思考,那么我们就能做出正确的选择,并且从新的Ajax技术和研究中获得好处。