深度解析ASP.NET中的Callback机制

  看到不少朋友最近在写使用callback的文章,也有点手痒,也来涂鸦一下,挖掘挖掘callback的潜力。callback的一般使用方法还算简单,直接参照msdn的帮助和范例就足够了。但是想要真正用好、用精,或者想开发一些基于callback机制的WEB组件,那么,就要先深入了解callback的实现机制了。在本文中,Teddy将和您一起解析callback的整个调用、反馈机制,相信对于帮助您更好的使用callback,将能有一定的益处。
  Callback vs ASP.NET AJAX
  首先,谈谈ASP.NET AJAX。很多朋友可能会觉得奇怪,已经有了Callback,为什么又要出ASP.NET AJAX呢?关于这个问题,ASP.NET AJAX的作者怎么解释,我倒没有去调查。只不过从我个人对callback和ASP.NET AJAX的使用感受来讲,觉得,callback作为一个接口和postback非常类似的实现,肯定是为了让用户类似使用postback来使用它。但是,它的这个类似postback的机制,应该说使用上还不是特别方便,也不易扩展,当然这是相比于其他的AJAX框架实现来说的。因此,微软方面借鉴了许多的已有的AJAX实现,如Prototype,Backbase以及AJAX.NET,并结合ASP.NET2.0的部分特有功能,发明了这样一个博采众长的AJAX框架。基于ASP.NET AJAX来开发AJAX应用有多好,很难量化的来说,但至少不比其他的这些AJAX框架来的差是肯定的,加上微软这个后台,以及像live.com这样的重量级站点的应用推广,其影响当然是值得期待的。
  不过,这也不是说callback实现没一无是处了,作为程序员,我们需要有正确的态度,在正确的使用情形,使用最正确的技术。没有哪一个框架是万能的,是适合任何使用环境的;就像大家都在争论那个软件开发方法最好,CMMi,RUP,XP,AGILE~~,其实,没有最好,最合适的才是最好的。我们最应该做的,是了解各种方案的原理和优缺点,从而,合理的使用正确的工具来解决实际问题。
  Begin from Client Script
  我们都知道,凡是AJAX,从底层来讲,无外乎两种实现机制:XMLHTTP以及IFRAME。在AJAX这个词获得广泛关注之前,其实,基于这两种底层实现的功能框架,或者基于这两种技术的无刷新效果实现就已经被广泛的使用了。当然,发展到今天,在使用接口方面,这些底层机制的细节往往被框架给隐藏了,使用接口变得越来越简单,用户只要调用这些简单接口,没有必要知道具体是怎么实现效果的了。
  不过,这里我们既然是要解析callback的实现机制,那还是让我们从一个callback调用的客户端脚本调用开始,看看,微软是怎么实现这个callback机制的。
  1、ClientScript.GetCallbackEventReference(...)
  要激发一个callback,首先,当然需要在客户端本中发出一个调用。一个典型的调用语法如下:

<script language="Javascript" type="text/Javascript">
function any_script_function(arg, context)
{
<%= ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context")%>;
}
</script>

  从以上代码我们可以很明白的看到,系统判断您的浏览器是否支持XMLHTTP或IFRAME,如果至少支持其中之一,则用相应的方法执行回调,否则当然就是提示错误了。回调的时候,采用post的方式,异步post到当前页面,然后等待回调结束,此时,由我们指定的返回数据处理script函数来处理返回的数据。
  看到这里,我还不知道服务端怎么处理这个根据传过来的参数解析、执行,并返回数据的过程。但是,我们已经知道,WebForm_DoCallback(...)将会将当前页面的web控件的信息都post回去,这就意味着,我们在服务端有可能可以访问到这些web控件的value,这还不错,方便了我们处理当前数据。另一方面,eventArgument既然是一个任意格式的字符串参数,我们肯定要在服务段自己解析它的。
  Serverside Callback Operation & Render
  好了,那么接下来就让我们来看看在服务端,ASP.NET都为我们做了些什么。
  首先,我们知道,当前的Page是必须实现ICallbackEventHandler这个接口的,也就是其包含的两个函数:string GetCallbackResult()和void RaiseCallbackEvent(eventArgument)。根据MSDN的文档,我们知道,在一个callback被post到服务端时,Page将会首先将post回来的form data绑定到当前页面的服务端web控件,接着判断本次post是callback还是postback,如果是postpost,那么自然是原来的那个机制;
  如果是callback,则将回调用触发本次callback的控件(在本例中,我们在激发这个callback时,第一个参数指定的是this也就是当前的Page,那么这里当前的Page就是这个触发控件)的RaiseCallbackEvent(eventArgument),当然,eventArgument也将会正确的传过来,在这个函数的实现代码里我们可以对这个参数进行解析处理,并在某个地方,存储我们准备返回的数据,或者待处理的已经被解析出来的参数;
  接着,系统将调用string GetCallbackResult(),在这个函数的实现代码中,我们可以直接返回我们在RaiseCallback函数中存储的准备返回的数据,或者根据待处理的已经被解析出来的参数处理这些参数,并返回结果。这个返回的字符串,自然将以脚本的形式被render回客户端。被返回的脚本细节如下(反编译Page.RenderCallback()的源码),我们可以看到,返回的结果除了我们需要的结果数据和相应的脚本,没有多余的数据,因此,callback的执行效率应该说还是不错的:

private void RenderCallback()
{
bool flag1 = !string.IsNullOrEmpty(this._requestValueCollection["__CALLBACKLOADSCRIPT"]);
try
{
string text1 = null;
if (flag1)
{
text1
= this._requestValueCollection["__CALLBACKINDEX"];
if (string.IsNullOrEmpty(text1))
{
throw new HttpException(SR.GetString("Page_CallBackInvalid"));
}
for (int num1 = 0; num1 < text1.Length; num1++)
{
if (!char.IsDigit(text1, num1))
{
throw new HttpException(SR.GetString("Page_CallBackInvalid"));
}
}
this.Response.Write("<script>parent.__pendingCallbacks[");
this.Response.Write(text1);
this.Response.Write("].xmlRequest.responseText=/"");
}
if (this._callbackControl != null)
{
string text2 = this._callbackControl.GetCallbackResult();
if (this.EnableEventValidation)
{
string text3 = this.ClientScript.GetEventValidationFieldValue();
this.Response.Write(text3.Length.ToString(CultureInfo.InvariantCulture));
this.Response.Write('|');
this.Response.Write(text3);
}
else
{
this.Response.Write('s');
}
this.Response.Write(flag1 ? Util.QuoteJScriptString(text2) : text2);
}
if (flag1)
{
this.Response.Write("/";parent.__pendingCallbacks[");
this.Response.Write(text1);
this.Response.Write("].xmlRequest.readyState=4;parent.WebForm_CallbackComplete();</script>");
}
}
catch (Exception exception1)
{
this.Response.Clear();
this.Response.Write('e');
if (this.Context.IsCustomErrorEnabled)
{
this.Response.Write(SR.GetString("Page_CallBackError"));
return;
}
this.Response.Write(flag1 ? Util.QuoteJScriptString(HttpUtility.HtmlEncode(exception1.Message)) : HttpUtility.HtmlEncode(exception1.Message));
}
}

NET技术深度解析ASP.NET中的Callback机制,转载需保留来源!

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。