【silverlightfans】asp.net 客戶端回撥功能的實現機制探討(請求部分)
實現的過程基本上就是:讓要實現客戶端回撥功能的頁面或者空間實現System.Web.UI.ICallbackEventHandler的介面,即2個方法:void RaiseCallbackEvent(string eventArgument),這個是當客戶端觸發伺服器端事件的委託方法,string GetCallbackResult();這個是返回客戶端需要的值,只能是string 型的,當然你也可以返回一個Json串。
然後在pageload的時候註冊指令碼到客戶端:在這裡註冊一個CallServer方法來呼叫伺服器端方法,ReceiveServerData來捕獲伺服器返回的結果。當然你也可以使用一個方法來捕獲伺服器端的錯誤,詳見Page.ClientScript.RegisterClientScriptBlock這個方法的MSDN解釋。
這樣就能實現客戶端的回撥伺服器端事件,並返回值。
生成好頁面後,檢視原始碼:
首先是多了一個js資原始檔,多了一行這樣的程式碼:
首先看js資原始檔(20多K,汗一個...)。先在資原始檔裡面找到這個方法,WebForm_InitCallback();
方法如下:
附WebForm_InitCallbackAddField(element.name, element.value);方法實現:
那麼就是asp.net在初始化客戶端回撥功能的時候,其實就是將表單裡面的所有鍵值對全部裝載到一個全域性的鍵值對裡面去了。
然後,我們們來看看unction CallServer(arg, context){ WebForm_DoCallback('__Page',arg,ReceiveServerData,context,null,false);}所作的工作。
在示例中,點選按鈕,就觸發了CallServer方法,
在資原始檔中找到WebForm_DoCallback方法,由於方法太長太大,只有分段解析:
不過俺們還忽略了一些細節,讓我們從頭再來。上面有一段程式碼
if (setRequestHeaderMethodExists)
也就是說在setRequestHeaderMethodExists這個變數不為null的時候才能夠傳送非同步物件,那麼這個變數是怎麼定義的呢??
然後在pageload的時候註冊指令碼到客戶端:在這裡註冊一個CallServer方法來呼叫伺服器端方法,ReceiveServerData來捕獲伺服器返回的結果。當然你也可以使用一個方法來捕獲伺服器端的錯誤,詳見Page.ClientScript.RegisterClientScriptBlock這個方法的MSDN解釋。
這樣就能實現客戶端的回撥伺服器端事件,並返回值。
生成好頁面後,檢視原始碼:
首先是多了一個js資原始檔,多了一行這樣的程式碼:
<SCRIPT type=text/javascript>
<!--
function CallServer(arg, context){ WebForm_DoCallback('__Page',arg,ReceiveServerData,context,null,false);}// -->
SCRIPT>
在body快結束的時候還有一段這樣的程式碼:<!--
function CallServer(arg, context){ WebForm_DoCallback('__Page',arg,ReceiveServerData,context,null,false);}// -->
SCRIPT>
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}
這個方法就是把表單裡面所有的值全部裝載到一個鍵值對裡面去。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) + "&";
}
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);
}
}
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, "");
}
{
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 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) {
}
}
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。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;
}
不過俺們還忽略了一些細節,讓我們從頭再來。上面有一段程式碼
if (setRequestHeaderMethodExists)
也就是說在setRequestHeaderMethodExists這個變數不為null的時候才能夠傳送非同步物件,那麼這個變數是怎麼定義的呢??
var setRequestHeaderMethodExists = true;
try {
setRequestHeaderMethodExists = (xmlRequest && xmlRequest.setRequestHeader);
}
也就是說只有當正確的建立了xmlRequest物件後才能夠使用ajax,那麼如果不能夠正確建立ajax物件怎麼辦呢?接著看程式碼!try {
setRequestHeaderMethodExists = (xmlRequest && xmlRequest.setRequestHeader);
}
callback.xmlRequest = new Object();
var callbackFrameID = "__CALLBACKFRAME" + callbackIndex;
var xmlRequestFrame = document.frames[callbackFrameID];
var callbackFrameID = "__CALLBACKFRAME" + callbackIndex;
var xmlRequestFrame = document.frames[callbackFrameID];
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-349305/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 退避演算法實現之客戶端優雅回撥演算法客戶端
- Swoole 協程 MySQL 客戶端與非同步回撥 MySQL 客戶端的對比MySql客戶端非同步
- jQuery實現客戶端CheckAll功能jQuery客戶端
- nginx截獲客戶端請求Nginx客戶端
- SimpleRpc-客戶端與服務端工作模型探討RPC客戶端服務端模型
- pycurl實現hadoop的客戶端功能薦Hadoop客戶端
- Java——回撥機制Java
- java 介面回撥經典案例--網路請求回撥Java
- FTP客戶端c程式碼功能實現FTP客戶端C程式
- 短影片原始碼,實現預處理防止客戶端頻繁請求原始碼客戶端
- Redis處理客戶端連線的內部實現機制RXRedis客戶端
- HBase最佳實踐-客戶端超時機制客戶端
- C++中實現回撥機制的幾種方式[轉]C++
- nginx 處理客戶端請求的完整過程Nginx客戶端
- 基於Microsoft visual c++ 6.0實現客戶端HTTP的Get、Post請求ROSC++客戶端HTTP
- JAX-RSREST客戶端實現基本身份驗證機制REST客戶端
- 回撥機制詳解
- 服務端如何獲取客戶端請求IP地址服務端客戶端
- 億憶網客戶端原始碼開源!歡迎探討!客戶端原始碼
- ajax--實現非同步請求,接受響應及執行回撥非同步
- 從客戶端向服務端發起請求(3種)客戶端服務端
- java回撥函式機制Java函式
- Java回撥機制解讀Java
- Android客戶端請求伺服器端的詳細解釋Android客戶端伺服器
- Nginx基於客戶端請求頭的訪問分類Nginx客戶端
- Sql Server深入的探討鎖機制SQLServer
- 客戶端骨架屏實現客戶端
- Spring Security 實戰乾貨:客戶端OAuth2授權請求的Spring客戶端OAuth
- 客戶端PC入網後DHCP請求過程(轉)客戶端
- 搭建本地server,響應Android客戶端HTTP請求ServerAndroid客戶端HTTP
- Java 回撥機制(CallBack) 趣解Java
- Java介面回撥機制詳解Java
- 深入淺出Java回撥機制Java
- C語言關於回撥函式和this指標探討C語言函式指標
- Redis的Pub/Sub客戶端實現Redis客戶端
- 網頁SSH客戶端的實現網頁客戶端
- ASP.Net請求處理機制初步探索之旅(5):ASP.Net MVC請求處理流程ASP.NETMVC
- Spring Security 實戰乾貨:客戶端OAuth2授權請求的入口Spring客戶端OAuth