远离UpdatePanel给我的噩梦
摘要:
自从项目要求启用ajax之后,一直都很头痛,直到ComponentArt放出支持ms asp.net ajax之后,所有的问题迎刃而解,于是乎立马down下ms asp.net ajax beta2,祭出神奇的UpdatePanel。但是正所谓“福之祸所依,祸兮福所至”,噩梦已经埋下伏笔......
一、噩梦的根源:庞大的页面
UpdatePanel在页面小的时候还是很好用的,而当页面控件数不断上升的时候,UpdatePanel就开始直线下降,我们现在页面有4,5百个控件,每做一次PostBack需要长达15秒钟之长,实在让人无法忍受。
二、救命稻草:ICallbackEventHandler
在实际应用中,我们很多页面同时也使用asp.net 2.0带的Callback机制,发现之间的速度差别不是一般大,那是相当的大阿。于是就萌发利用Callback的机制,制作一个替代UpdatePanel的框架。记得Teddy的AjaxHelper好像是基于Callback实现了,故下载了其框架的范例,发现和自己的想法还是有一定的出入,要直接转移到自己现有的Web框架来,改动量太大,所以,觉得自己写一个这样的框架会更好,不为重复发明轮子,而在于可以减少现有项目重构过程中的改动量。
三、CallbackPlus:
我把这个框架命名为:CallbackPlus,因为其完全是基于Callback机制来做的。
既然基于Callback机制,就有必要了解Callback的运行机制(详见Teddy的深度解析Asp.Net2.0中的Callback机制):
<script language="javascript" type="text/javascript"> function docallback(arg, context) { <%= ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context")%>; } </script>
<script type="text/javascript"> function ReceiveServerData(result, context) { //TODO } </script> 注册调用的script:docallback和接受的script:ReceiveServerData.
CallbackPlus原型就是这么的简单,它的即有功能也就是传递一个string参数,再返回一个string而已。
即然把CallbackPlus命名为一个框架,那似乎不该如此简陋吧,起码也应该把这些个手工注册的烦人工作进行下封装。或许有见过或者使用过Ajax.net的朋友都知道其异步事件的注册方法...嘿嘿,所谓大树底下好乘凉,我也没有必要自己寻找一个方式了,依葫芦画票也使用Attribute来实现(其实我已经深深的爱上了Attribute,哦也,反射,注入......,所有的实现一下子都变大那么的高雅迷人.)
server: [CallbackMethod] public void TestMethod1() { //TODO: }
client: <script> function doCallback(){ TestMethod1(); } </scipt> 在这里通过CallbackMethod的标签将客户端的方法与服务端的方法一一映射起来。
四、Reflect,json让string插上梦想的翅膀:
这样子的功能,实在是不堪大用,只有进一步封装Callback的细节,才可以派上用场。而Callback的实现又是那么的简陋,简陋到只有一个接口ICallbackEventHandler两个方法
public string GetCallbackResult(); public void RaiseCallbackEvent(string eventArgument); 而当string eventArgument 和return string这两段string结合reflect和json的时候,就可以发挥出不一般的作用。我们可以实现的目标:
- 让js的方法和cs的方法一一映射
- 让方法的参数和返回值也一一映射
- 让js的Object和cs的Class也一一映射
而实现这些的关键所在在于拦截docallback,ICallbackEventHandler的两个方法,ReceiveServerData的调用。关键的js代码:
<script type=\"text/javascript\"> var CallbackPlus = function(){ return{ DoCallback:function(target,arg,f,context){ WebForm_DoCallback(target,arg,f,context,null,true); }, OnCompleted:function(result,f){ var arguments; try{arguments = result.parseJSON();}catch(ex){arguments=result;}; if(arguments){ if(arguments[0]){alert(arguments[0]);}; " + if(arguments[1]){eval(arguments[1]);}; if(arguments[2]){ var obj; try{obj = arguments[2].parseJSON();}catch(ex){obj = arguments[2];} f.call(this,obj); }; }; } }; }();function onCompleted(){};</script> 或许例子更能说明我的意图,请看Demo代码:CallbackPlusDemo.rar
五、后话:
当然这样子的js的取数将成为一个极大的工作量,但是可以在js写一个专门收集form数据的函数,这样子配合CallbackPlus则可实现完全自动的收集数据和更新数据。
目前框架刚刚投入使用,有兴趣的朋友不妨帮忙测试,发现bug希望可以通知我。谢谢
更新 07-01-09 22:10:
更正自己的一个观点:Callback无法取到控件的新的值。仔细看了下Teddy中文章的讨论,发现Callback照样可以取到控件的新值,真是爽,项目的重构又少了点,不过又担心这个回传是不是会恢复到使用UpdatePanel时候的速度,看来还是需要大页面测试一下.修改CallbackMethod和js增加Postdata的控制设定
<script type=\"text/javascript\">
var CallbackPlus = function(){
return{
DoCallback:function(target,arg,f,context,isPostdata){
if(isPostdata){
__theFormPostData = \"\";
__theFormPostCollection = new Array();
WebForm_InitCallback();
}
WebForm_DoCallback(target,arg,f,context,null,true);
},
OnCompleted:function(result,f){
var arguments;
try{arguments = result.parseJSON();}catch(ex){arguments=result;};
if(arguments){
if(arguments[0]){alert(arguments[0]);};
if(arguments[1]){eval(arguments[1]);};
if(arguments[2]){
var obj;
try{obj = arguments[2].parseJSON();}catch(ex){obj = arguments[2];}
f.call(this,obj);
};
};
}
};
}();</script>