[CallbackPlus]远离UpdatePanel给我的噩梦

 

********************************************************************
*                                                 版权声明
*
* 本文以Creative Commons的知识共享署名-非商业性使用-相同方式共享发布,请严格遵循该授权协议。
* 本文首发于博客园, 此声明为本文章中不可或缺的一部分。
* 作者网名:    浪子
* 作者EMAILdayichen (at)163.com
* 作者BLOG:  Http://Www.Cnblogs.Com/Walkingboy
*
********************************************************************

[CallbackPlus]远离UpdatePanel给我的噩梦

-Written by 浪子@cnblogs.com  (07-01-09)

摘要:

自从项目要求启用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>
posted @ 2007-01-09 13:46  浪子  阅读(5307)  评论(54编辑  收藏