【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)

iDotNetSpace發表於2008-06-16
實現的過程基本上就是:讓要實現客戶端回撥功能的頁面或者空間實現System.Web.UI.ICallbackEventHandler的介面,即2個方法:void RaiseCallbackEvent(string eventArgument),這個是當客戶端觸發伺服器端事件的委託方法,string GetCallbackResult();這個是返回客戶端需要的值,只能是string 型的,當然你也可以返回一個Json串。
然後在pageload的時候註冊指令碼到客戶端:在這裡註冊一個CallServer方法來呼叫伺服器端方法,ReceiveServerData來捕獲伺服器返回的結果。當然你也可以使用一個方法來捕獲伺服器端的錯誤,詳見Page.ClientScript.RegisterClientScriptBlock這個方法的MSDN解釋。
這樣就能實現客戶端的回撥伺服器端事件,並返回值。
生成好頁面後,檢視原始碼:
首先是多了一個js資原始檔,多了一行這樣的程式碼:
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)<SCRIPT type=text/javascript>
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)
<!--
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)
function CallServer(arg, context){ WebForm_DoCallback('__Page',arg,ReceiveServerData,context,null,false);}// --&gt
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)
SCRIPT>
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)
在body快結束的時候還有一段這樣的程式碼:
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)WebForm_InitCallback();
好,這些應該就是asp.net為了實現客戶端回撥所作的補充工作了吧,我們們來研究吧。
首先看js資原始檔(20多K,汗一個...)。先在資原始檔裡面找到這個方法,WebForm_InitCallback();
方法如下:
 1【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)function WebForm_InitCallback() {
 2【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    var count = theForm.elements.length;
 3【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    var element;
 4【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    for (var i = 0; i < count; i++{
 5【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        element = theForm.elements[i];
 6【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        var tagName = element.tagName.toLowerCase();
 7【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        if (tagName == "input"{
 8【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)            var type = element.type;
 9【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)            if ((type == "text" || type == "hidden" || type == "password" ||
10【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)                ((type == "checkbox" || type == "radio"&& element.checked)) &&
11【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)                (element.id != "__EVENTVALIDATION")) {
12【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)                WebForm_InitCallbackAddField(element.name, element.value);
13【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)            }

14【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        }

15【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        else if (tagName == "select"{
16【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)            var selectCount = element.options.length;
17【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)            for (var j = 0; j < selectCount; j++{
18【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)                var selectChild = element.options[j];
19【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)                if (selectChild.selected == true{
20【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)                    WebForm_InitCallbackAddField(element.name, element.value);
21【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)                }

22【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)            }

23【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        }

24【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        else if (tagName == "textarea"{
25【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)            WebForm_InitCallbackAddField(element.name, element.value);
26【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        }

27【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    }

28【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)}
這個方法就是把表單裡面所有的值全部裝載到一個鍵值對裡面去。
附WebForm_InitCallbackAddField(element.name, element.value);方法實現:
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)function WebForm_InitCallbackAddField(name, value) {
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    
var nameValue = new Object();
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    nameValue.name 
= name;
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    nameValue.value 
= value;
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    __theFormPostCollection[__theFormPostCollection.length] 
= nameValue;
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    __theFormPostData 
+= name + "=" + WebForm_EncodeCallback(value) + "&";
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)}

【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)function WebForm_EncodeCallback(parameter) {
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    
if (encodeURIComponent) {
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        
return encodeURIComponent(parameter);
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    }

【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    
else {
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        
return escape(parameter);
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    }

【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)}

那麼就是asp.net在初始化客戶端回撥功能的時候,其實就是將表單裡面的所有鍵值對全部裝載到一個全域性的鍵值對裡面去了。

然後,我們們來看看unction CallServer(arg, context){ WebForm_DoCallback('__Page',arg,ReceiveServerData,context,null,false);}所作的工作。
在示例中,點選按鈕,就觸發了CallServer方法,

【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)function LookUpStock()
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    
{
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        
var lb = document.getElementById("ListBox1");
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        
var product = lb.options[lb.selectedIndex].text;
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        CallServer(product, 
"");
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    }

在資原始檔中找到WebForm_DoCallback方法,由於方法太長太大,只有分段解析:
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)unction WebForm_DoCallback(eventTarget, eventArgument, eventCallback, context, errorCallback, useAsync) {
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    
var postData = __theFormPostData +
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)                
"__CALLBACKID=" + WebForm_EncodeCallback(eventTarget) +
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)                
"&__CALLBACKPARAM=" + WebForm_EncodeCallback(eventArgument);
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    
if (theForm["__EVENTVALIDATION"]) {
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        postData 
+= "&__EVENTVALIDATION=" + WebForm_EncodeCallback(theForm["__EVENTVALIDATION"].value);
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    }

【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    
var xmlRequest,e;
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    
try {
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        xmlRequest 
= new XMLHttpRequest();
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    }

【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    
catch(e) {
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        
try {
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)            xmlRequest 
= new ActiveXObject("Microsoft.XMLHTTP");
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        }

【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        
catch(e) {
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        }

【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    }
這段程式碼是將一些引數附加上去到postData變數上。並建立xmlRequest物件。不過這個建立非同步物件方法似乎有點不妥,他是先看是否是非IE的瀏覽器,然後被cacth住了才建立ActiveX物件,也就是說在IE大行其道的時候不得不多次catch,為什麼不把建立ActiveX物件放在前面節省資源呢?不管這麼多,接下來看:
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)var setRequestHeaderMethodExists = true;
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    
try {
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        setRequestHeaderMethodExists 
= (xmlRequest && xmlRequest.setRequestHeader);
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    }

【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    
catch(e) {}
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    
var callback = new Object();
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    callback.eventCallback 
= eventCallback;
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    callback.context 
= context;
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    callback.errorCallback 
= errorCallback;
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    callback.async 
= useAsync;
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    
var callbackIndex = WebForm_FillFirstAvailableSlot(__pendingCallbacks, callback);
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    
if (!useAsync) {
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        
if (__synchronousCallBackIndex != -1{
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)            __pendingCallbacks[__synchronousCallBackIndex] 
= null;
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        }

【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        __synchronousCallBackIndex 
= callbackIndex;
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    }

【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    
if (setRequestHeaderMethodExists) {
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        xmlRequest.onreadystatechange 
= WebForm_CallbackComplete;
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        callback.xmlRequest 
= xmlRequest;
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        xmlRequest.open(
"POST", theForm.action, true);
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        xmlRequest.setRequestHeader(
"Content-Type""application/x-www-form-urlencoded");
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        xmlRequest.send(postData);
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        
return;
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    }
這幾段語句最重要的是將非同步回撥方法賦值為:WebForm_CallbackComplete。

不過俺們還忽略了一些細節,讓我們從頭再來。上面有一段程式碼
if (setRequestHeaderMethodExists)
也就是說在setRequestHeaderMethodExists這個變數不為null的時候才能夠傳送非同步物件,那麼這個變數是怎麼定義的呢??
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)var setRequestHeaderMethodExists = true;
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    
try {
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)        setRequestHeaderMethodExists 
= (xmlRequest && xmlRequest.setRequestHeader);
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    }
也就是說只有當正確的建立了xmlRequest物件後才能夠使用ajax,那麼如果不能夠正確建立ajax物件怎麼辦呢?接著看程式碼!

【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)callback.xmlRequest = new Object();
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    
var callbackFrameID = "__CALLBACKFRAME" + callbackIndex;
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)    
var xmlRequestFrame = document.frames[callbackFrameID];
【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-349305/,如需轉載,請註明出處,否則將追究法律責任。

相關文章