|
看到不少朋友最近在寫使用callback的文章,也有點(diǎn)手癢,也來(lái)涂鴉一下,挖掘挖掘callback的潛力。callback的一般使用方法還算簡(jiǎn)單,直接參照msdn的幫助和范例就足夠了。但是想要真正用好、用精,或者想開發(fā)一些基于callback機(jī)制的WEB組件,那么,就要先深入了解callback的實(shí)現(xiàn)機(jī)制了。在本文中,Teddy將和您一起解析callback的整個(gè)調(diào)用、反饋機(jī)制,相信對(duì)于幫助您更好的使用callback,將能有一定的益處。
Callback vs ASP.NET AJAX
首先,談?wù)?a href=/itjie/ASPjishu/ target=_blank class=infotextkey>ASP.NET AJAX。很多朋友可能會(huì)覺得奇怪,已經(jīng)有了Callback,為什么又要出ASP.NET AJAX呢?關(guān)于這個(gè)問(wèn)題,ASP.NET AJAX的作者怎么解釋,我倒沒有去調(diào)查。只不過(guò)從我個(gè)人對(duì)callback和ASP.NET AJAX的使用感受來(lái)講,覺得,callback作為一個(gè)接口和postback非常類似的實(shí)現(xiàn),肯定是為了讓用戶類似使用postback來(lái)使用它。但是,它的這個(gè)類似postback的機(jī)制,應(yīng)該說(shuō)使用上還不是特別方便,也不易擴(kuò)展,當(dāng)然這是相比于其他的AJAX框架實(shí)現(xiàn)來(lái)說(shuō)的。因此,微軟方面借鑒了許多的已有的AJAX實(shí)現(xiàn),如Prototype,Backbase以及AJAX.NET,并結(jié)合ASP.NET2.0的部分特有功能,發(fā)明了這樣一個(gè)博采眾長(zhǎng)的AJAX框架。基于ASP.NET AJAX來(lái)開發(fā)AJAX應(yīng)用有多好,很難量化的來(lái)說(shuō),但至少不比其他的這些AJAX框架來(lái)的差是肯定的,加上微軟這個(gè)后臺(tái),以及像live.com這樣的重量級(jí)站點(diǎn)的應(yīng)用推廣,其影響當(dāng)然是值得期待的。
不過(guò),這也不是說(shuō)callback實(shí)現(xiàn)沒一無(wú)是處了,作為程序員,我們需要有正確的態(tài)度,在正確的使用情形,使用最正確的技術(shù)。沒有哪一個(gè)框架是萬(wàn)能的,是適合任何使用環(huán)境的;就像大家都在爭(zhēng)論那個(gè)軟件開發(fā)方法最好,CMMi,RUP,XP,AGILE~~,其實(shí),沒有最好,最合適的才是最好的。我們最應(yīng)該做的,是了解各種方案的原理和優(yōu)缺點(diǎn),從而,合理的使用正確的工具來(lái)解決實(shí)際問(wèn)題。
Begin from Client Script
我們都知道,凡是AJAX,從底層來(lái)講,無(wú)外乎兩種實(shí)現(xiàn)機(jī)制:XMLHTTP以及IFRAME。在AJAX這個(gè)詞獲得廣泛關(guān)注之前,其實(shí),基于這兩種底層實(shí)現(xiàn)的功能框架,或者基于這兩種技術(shù)的無(wú)刷新效果實(shí)現(xiàn)就已經(jīng)被廣泛的使用了。當(dāng)然,發(fā)展到今天,在使用接口方面,這些底層機(jī)制的細(xì)節(jié)往往被框架給隱藏了,使用接口變得越來(lái)越簡(jiǎn)單,用戶只要調(diào)用這些簡(jiǎn)單接口,沒有必要知道具體是怎么實(shí)現(xiàn)效果的了。
不過(guò),這里我們既然是要解析callback的實(shí)現(xiàn)機(jī)制,那還是讓我們從一個(gè)callback調(diào)用的客戶端腳本調(diào)用開始,看看,微軟是怎么實(shí)現(xiàn)這個(gè)callback機(jī)制的。
1、ClientScript.GetCallbackEventReference(...)
要激發(fā)一個(gè)callback,首先,當(dāng)然需要在客戶端本中發(fā)出一個(gè)調(diào)用。一個(gè)典型的調(diào)用語(yǔ)法如下:
<script language="Javascript" type="text/Javascript">
function any_script_function(arg, context)
{
<%= ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context")%>;
}
</script>從以上代碼我們可以很明白的看到,系統(tǒng)判斷您的瀏覽器是否支持XMLHTTP或IFRAME,如果至少支持其中之一,則用相應(yīng)的方法執(zhí)行回調(diào),否則當(dāng)然就是提示錯(cuò)誤了。回調(diào)的時(shí)候,采用post的方式,異步post到當(dāng)前頁(yè)面,然后等待回調(diào)結(jié)束,此時(shí),由我們指定的返回?cái)?shù)據(jù)處理script函數(shù)來(lái)處理返回的數(shù)據(jù)。
看到這里,我還不知道服務(wù)端怎么處理這個(gè)根據(jù)傳過(guò)來(lái)的參數(shù)解析、執(zhí)行,并返回?cái)?shù)據(jù)的過(guò)程。但是,我們已經(jīng)知道,WebForm_DoCallback(...)將會(huì)將當(dāng)前頁(yè)面的web控件的信息都post回去,這就意味著,我們?cè)诜?wù)端有可能可以訪問(wèn)到這些web控件的value,這還不錯(cuò),方便了我們處理當(dāng)前數(shù)據(jù)。另一方面,eventArgument既然是一個(gè)任意格式的字符串參數(shù),我們肯定要在服務(wù)段自己解析它的。
Serverside Callback Operation & Render
好了,那么接下來(lái)就讓我們來(lái)看看在服務(wù)端,ASP.NET都為我們做了些什么。
首先,我們知道,當(dāng)前的Page是必須實(shí)現(xiàn)ICallbackEventHandler這個(gè)接口的,也就是其包含的兩個(gè)函數(shù):string GetCallbackResult()和void RaiseCallbackEvent(eventArgument)。根據(jù)MSDN的文檔,我們知道,在一個(gè)callback被post到服務(wù)端時(shí),Page將會(huì)首先將post回來(lái)的form data綁定到當(dāng)前頁(yè)面的服務(wù)端web控件,接著判斷本次post是callback還是postback,如果是postpost,那么自然是原來(lái)的那個(gè)機(jī)制;
如果是callback,則將回調(diào)用觸發(fā)本次callback的控件(在本例中,我們?cè)诩ぐl(fā)這個(gè)callback時(shí),第一個(gè)參數(shù)指定的是this也就是當(dāng)前的Page,那么這里當(dāng)前的Page就是這個(gè)觸發(fā)控件)的RaiseCallbackEvent(eventArgument),當(dāng)然,eventArgument也將會(huì)正確的傳過(guò)來(lái),在這個(gè)函數(shù)的實(shí)現(xiàn)代碼里我們可以對(duì)這個(gè)參數(shù)進(jìn)行解析處理,并在某個(gè)地方,存儲(chǔ)我們準(zhǔn)備返回的數(shù)據(jù),或者待處理的已經(jīng)被解析出來(lái)的參數(shù);
接著,系統(tǒng)將調(diào)用string GetCallbackResult(),在這個(gè)函數(shù)的實(shí)現(xiàn)代碼中,我們可以直接返回我們?cè)赗aiseCallback函數(shù)中存儲(chǔ)的準(zhǔn)備返回的數(shù)據(jù),或者根據(jù)待處理的已經(jīng)被解析出來(lái)的參數(shù)處理這些參數(shù),并返回結(jié)果。這個(gè)返回的字符串,自然將以腳本的形式被render回客戶端。被返回的腳本細(xì)節(jié)如下(反編譯Page.RenderCallback()的源碼),我們可以看到,返回的結(jié)果除了我們需要的結(jié)果數(shù)據(jù)和相應(yīng)的腳本,沒有多余的數(shù)據(jù),因此,callback的執(zhí)行效率應(yīng)該說(shuō)還是不錯(cuò)的: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技術(shù):深度解析ASP.NET中的Callback機(jī)制,轉(zhuǎn)載需保留來(lái)源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。