asp.net用戶端回調功能的實現機制

來源:互聯網
上載者:User

 實現的過程基本上就是:讓要實現用戶端回調功能的頁面或者空間實現System.Web.UI.ICallbackEventHandler的介面,即2個方法:void RaiseCallbackEvent(string eventArgument),這個是當用戶端觸發伺服器端事件的委託方法,string GetCallbackResult();這個是返回用戶端需要的值,只能是string 型的,當然你也可以返回一個Json串。
然後在pageload的時候註冊指令碼到用戶端:在這裡註冊一個CallServer方法來調用伺服器端方法,ReceiveServerData來捕獲伺服器返回的結果。當然你也可以使用一個方法來捕獲伺服器端的錯誤,詳見Page.ClientScript.RegisterClientScriptBlock這個方法的MSDN解釋。
這樣就能實現用戶端的回調伺服器端事件,並傳回值。
產生好頁面後,查看原始碼:
首先是多了一個js資源檔,多了一行這樣的代碼:

在body快結束的時候還有一段這樣的代碼:
WebForm_InitCallback();好,這些應該就是asp.net為了實現用戶端回調所作的補充工作了吧,咱們來研究吧。
首先看js資源檔(20多K,汗一個...)。先在資源檔裡面找到這個方法,WebForm_InitCallback();
方法如下:
1function WebForm_InitCallback() {
2 var count = theForm.elements.length;
3 var element;
4 for (var i = 0; i < count; i++) {
5 element = theForm.elements[i];
6 var tagName = element.tagName.toLowerCase();
7 if (tagName == "input") {
8 var type = element.type;
9 if ((type == "text"    type == "hidden"    type == "password"   
10 ((type == "checkbox"    type == "radio") & element.checked)) &&
11 (element.id != "__EVENTVALIDATION")) {
12 WebForm_InitCallbackAddField(element.name, element.value);
13 }
14 }
15 else if (tagName == "select") {
16 var selectCount = element.options.length;
17 for (var j = 0; j < selectCount; j++) {
18 var selectChild = element.options[j];
19 if (selectChild.selected == true) {
20 WebForm_InitCallbackAddField(element.name, element.value);
21 }
22 }
23 }
24 else if (tagName == "textarea") {
25 WebForm_InitCallbackAddField(element.name, element.value);
26 }
27 }
28}這個方法就是把表單裡面所有的值全部裝載到一個索引值對裡面去。
附WebForm_InitCallbackAddField(element.name, element.value);方法實現:
function WebForm_InitCallbackAddField(name, value) {
var nameValue = new Object();
nameValue.name = name;
nameValue.value = value;
__theFormPostCollection[__theFormPostCollection.length] = nameValue;
__theFormPostData += name + "=" + WebForm_EncodeCallback(value) + "&";
}
function WebForm_EncodeCallback(parameter) {
if (encodeURIComponent) {
return encodeURIComponent(parameter);
}
else {
return escape(parameter);
}
}
那麼就是asp.net在初始化用戶端回調功能的時候,其實就是將表單裡面的所有索引值對全部裝載到一個全域的索引值對裡面去了。

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

function LookUpStock()
{
var lb = document.getElementById("ListBox1");
var product = lb.options[lb.selectedIndex].text;
CallServer(product, "");
}
在資源檔中找到WebForm_DoCallback方法,由於方法太長太大,只有分段解析:
unction WebForm_DoCallback(eventTarget, eventArgument, eventCallback, context, errorCallback, useAsync) {
var postData = __theFormPostData +
"__CALLBACKID=" + WebForm_EncodeCallback(eventTarget) +
"&__CALLBACKPARAM=" + WebForm_EncodeCallback(eventArgument);
if (theForm["__EVENTVALIDATION"]) {
postData += "&__EVENTVALIDATION=" + WebForm_EncodeCallback(theForm["__EVENTVALIDATION"].value);
}
var xmlRequest,e;
try {
xmlRequest = new XMLHttpRequest();
}
catch(e) {
try {
xmlRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
catch(e) {
}
}這段代碼是將一些參數附加上去到postData變數上。並建立xmlRequest對象。不過這個建立非同步對象方法似乎有點不妥,他是先看是否是非IE的瀏覽器,然後被cacth住了才建立ActiveX對象,也就是說在IE大行其道的時候不得不多次catch,為什麼不把建立ActiveX對象放在前面節省資源呢?不管這麼多,接下來看:
var setRequestHeaderMethodExists = true;
try {
setRequestHeaderMethodExists = (xmlRequest && xmlRequest.setRequestHeader);
}
catch(e) {}
var callback = new Object();
callback.eventCallback = eventCallback;
callback.context = context;
callback.errorCallback = errorCallback;
callback.async = useAsync;
var callbackIndex = WebForm_FillFirstAvailableSlot(__pendingCallbacks, callback);
if (!useAsync) {
if (__synchronousCallBackIndex != -1) {
__pendingCallbacks[__synchronousCallBackIndex] = null;
}
__synchronousCallBackIndex = callbackIndex;
}
if (setRequestHeaderMethodExists) {
xmlRequest.onreadystatechange = WebForm_CallbackComplete;
callback.xmlRequest = xmlRequest;
xmlRequest.open("POST", theForm.action, true);
xmlRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlRequest.send(postData);
return;
}這幾段語句最重要的是將非同步回調方法賦值為:WebForm_CallbackComplete。

不過俺們還忽略了一些細節,讓我們從頭再來。上面有一段代碼
if (setRequestHeaderMethodExists)
也就是說在setRequestHeaderMethodExists這個變數不為null的時候才能夠發送非同步對象,那麼這個變數是怎麼定義的呢??
var setRequestHeaderMethodExists = true;
try {
setRequestHeaderMethodExists = (xmlRequest && xmlRequest.setRequestHeader);
}也就是說只有當正確的建立了xmlRequest對象後才能夠使用ajax,那麼如果不能夠正確建立ajax對象怎麼辦呢?接著看代碼!

callback.xmlRequest = new Object();
var callbackFrameID = "__CALLBACKFRAME" + callbackIndex;
var xmlRequestFrame = document.frames[callbackFrameID];
if (!xmlRequestFrame) {
xmlRequestFrame = document.createElement("IFRAME");
xmlRequestFrame.width = "1";
xmlRequestFrame.height = "1";
xmlRequestFrame.frameBorder = "0";
xmlRequestFrame.id = callbackFrameID;
xmlRequestFrame.name = callbackFrameID;
xmlRequestFrame.style.position = "absolute";
xmlRequestFrame.style.top = "-100px"
xmlRequestFrame.style.left = "-100px";
try {
if (callBackFrameUrl) {
xmlRequestFrame.src = callBackFrameUrl;
}
}
catch(e) {}
document.body.appendChild(xmlRequestFrame);
}接下來原來是建立一個iframe!呵呵,原來是保證所有的瀏覽器都能使用ajax才出的這招。
再下來應該就是給這個iframe裡面載入一些變數了,並且提交這個iframe了:
var interval = window.setInterval(function() {
xmlRequestFrame = document.frames[callbackFrameID];
if (xmlRequestFrame && xmlRequestFrame.document) {
window.clearInterval(interval);
xmlRequestFrame.document.write("");
xmlRequestFrame.document.close();
xmlRequestFrame.document.write('

');
xmlRequestFrame.document.close();
xmlRequestFrame.document.forms[0].action = theForm.action;
var count = __theFormPostCollection.length;
var element;
for (var i = 0; i < count; i++) {
element = __theFormPostCollection[i];
if (element) {
var fieldElement = xmlRequestFrame.document.createElement("INPUT");
fieldElement.type = "hidden";
fieldElement.name = element.name;
fieldElement.value = element.value;
xmlRequestFrame.document.forms[0].appendChild(fieldElement);
}
}
var callbackIdFieldElement = xmlRequestFrame.document.createElement("INPUT");
callbackIdFieldElement.type = "hidden";
callbackIdFieldElement.name = "__CALLBACKID";
callbackIdFieldElement.value = eventTarget;
xmlRequestFrame.document.forms[0].appendChild(callbackIdFieldElement);
var callbackParamFieldElement = xmlRequestFrame.document.createElement("INPUT");
callbackParamFieldElement.type = "hidden";
callbackParamFieldElement.name = "__CALLBACKPARAM";
callbackParamFieldElement.value = eventArgument;
xmlRequestFrame.document.forms[0].appendChild(callbackParamFieldElement);
if (theForm["__EVENTVALIDATION"]) {
var callbackValidationFieldElement = xmlRequestFrame.document.createElement("INPUT");
callbackValidationFieldElement.type = "hidden";
callbackValidationFieldElement.name = "__EVENTVALIDATION";
callbackValidationFieldElement.value = theForm["__EVENTVALIDATION"].value;
xmlRequestFrame.document.forms[0].appendChild(callbackValidationFieldElement);
}
var callbackIndexFieldElement = xmlRequestFrame.document.createElement("INPUT");
callbackIndexFieldElement.type = "hidden";
callbackIndexFieldElement.name = "__CALLBACKINDEX";
callbackIndexFieldElement.value = callbackIndex;
xmlRequestFrame.document.forms[0].appendChild(callbackIndexFieldElement);
xmlRequestFrame.document.forms[0].submit();
}
}, 10);
}
原來在最開始初始化用戶端回調的方法就是為了在不能夠正確建立ajax對象的時候,將表單的值全部初始化到另外的iframe裡面去的。
好了,整個asp.net用戶端回調的請求發送部分分析完了
 
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.