深度解析ASP.NET2.0中的Callback机制(2)
点击次数:21 次 发布日期:2008-11-26 15:07:55 作者:源代码网
|
源代码网推荐 源代码网推荐 Ok,明白了以上代码的含义,下面我们来看看,前面的这条“<%= ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context")%>;”在运行时会被解析成什么样子呢?我们只要在页面运行时察看页面源码就可以看到,实际上服务器帮我们生成了下面这段script代码: 源代码网推荐 源代码网推荐 <script language="JavaScript" type="text/Javascript"> 源代码网推荐 function any_script_function() 源代码网推荐 { 源代码网推荐 WebForm_DoCallback("__Page",arg,ReceiveServerData,context,null,false); 源代码网推荐 } 源代码网推荐 </script> 源代码网推荐 源代码网推荐 这段代码是什么意思呢?很显然的他调用了一个系统与定义的script函数:WebForm_DoCallback。我们要把这个函数找出来看看它具体为我们干了什么。在运行时的页面源码中,我们很容易可以找到这段脚本的出处。我们注意到有一个script,src="http://www.zzchn.com/TestCallbackWeb/WebResource.axd?d=HEcYmh-7_szSIu1D_mHSEw2&t=632661779991718750",这里就定义了WebForm_DoCallback。让我们把它用Flashget下载下来,将扩展名改为.js。看看源码吧,没有被混淆的,所以很容易看明白。我这里就只把和callback相关的部分贴出来解释一下,见代码中的注释: 源代码网推荐 源代码网推荐 //用于存放所有未完成的callback对象的数组__pendingCallbacks 源代码网推荐 var __pendingCallbacks = new Array(); 源代码网推荐 var __synchronousCallBackIndex = -1; 源代码网推荐 源代码网推荐 //回调主函数WebForm_DoCallback 源代码网推荐 function WebForm_DoCallback(eventTarget, eventArgument, eventCallback, context, errorCallback, useAsync) { 源代码网推荐 源代码网推荐 //构造回调参数,回调参数包括了原来页面上的formpostdata和我们传递的目标控件、eventArgument和部分验证信息 源代码网推荐 var postData = __theFormPostData + 源代码网推荐 "__CALLBACKID=" + WebForm_EncodeCallback(eventTarget) + 源代码网推荐 "&__CALLBACKPARAM=" + WebForm_EncodeCallback(eventArgument); 源代码网推荐 if (theForm["__EVENTVALIDATION"]) { 源代码网推荐 postData += "&__EVENTVALIDATION=" + WebForm_EncodeCallback(theForm["__EVENTVALIDATION"].value); 源代码网推荐 } 源代码网推荐 源代码网推荐 //下面实例化XMLHTTP对象,如果浏览器支持XMLHTTP则直接用XMLHTTP执行异步回调 源代码网推荐 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; 源代码网推荐 } 源代码网推荐 源代码网推荐 //万一浏览器不支持XMLHTTP的话,我们IFRAME方案代替,在一个隐藏的IFRAME中执行Postback 源代码网推荐 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); 源代码网推荐 } 源代码网推荐 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("<html><body><form method="post"><input type="hidden" name="__CALLBACKLOADSCRIPT" value="t"></form></body></html>"); 源代码网推荐 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); 源代码网推荐 } 源代码网推荐 源代码网推荐 //该函数在每次回调结束后会调用来检查当前的回调列表中的回调的执行情况,如果,执行完毕的,则从列表中删除回调对象,并删除临时建立的IFRAME 源代码网推荐 function WebForm_CallbackComplete() { 源代码网推荐 for (i = 0; i < __pendingCallbacks.length; i++) { 源代码网推荐 callbackObject = __pendingCallbacks[i]; 源代码网推荐 if (callbackObject && callbackObject.xmlRequest && (callbackObject.xmlRequest.readyState == 4)) { 源代码网推荐 WebForm_ExecuteCallback(callbackObject); 源代码网推荐 if (!__pendingCallbacks[i].async) { 源代码网推荐 __synchronousCallBackIndex = -1; 源代码网推荐 } 源代码网推荐 __pendingCallbacks[i] = null; 源代码网推荐 var callbackFrameID = "__CALLBACKFRAME" + i; 源代码网推荐 var xmlRequestFrame = document.getElementById(callbackFrameID); 源代码网推荐 if (xmlRequestFrame) { 源代码网推荐 xmlRequestFrame.parentNode.removeChild(xmlRequestFrame); 源代码网推荐 } 源代码网推荐 } 源代码网推荐 } 源代码网推荐 } 源代码网推荐 源代码网推荐 //该函数执行我们在回调激发端指定的处理返回数据的script函数,如我们上面范例代码中的ReceiveServerData函数 源代码网推荐 function WebForm_ExecuteCallback(callbackObject) { 源代码网推荐 var response = callbackObject.xmlRequest.responseText; 源代码网推荐 if (response.charAt(0) == "s") { 源代码网推荐 if ((typeof(callbackObject.eventCallback) != "undefined") && (callbackObject.eventCallback != null)) { 源代码网推荐 callbackObject.eventCallback(response.substring(1), callbackObject.context); 源代码网推荐 } 源代码网推荐 } 源代码网推荐 else if (response.charAt(0) == "e") { 源代码网推荐 if ((typeof(callbackObject.errorCallback) != "undefined") && (callbackObject.errorCallback != null)) { 源代码网推荐 callbackObject.errorCallback(response.substring(1), callbackObject.context); 源代码网推荐 } 源代码网推荐 } 源代码网推荐 else { 源代码网推荐 var separatorIndex = response.indexOf("|"); 源代码网推荐 if (separatorIndex != -1) { 源代码网推荐 var validationFieldLength = parseInt(response.substring(0, separatorIndex)); 源代码网推荐 if (!isNaN(validationFieldLength)) { 源代码网推荐 var validationField = response.substring(separatorIndex + 1, separatorIndex + validationFieldLength + 1); 源代码网推荐 if (validationField != "") { 源代码网推荐 var validationFieldElement = theForm["__EVENTVALIDATION"]; 源代码网推荐 if (!validationFieldElement) { 源代码网推荐 validationFieldElement = document.createElement("INPUT"); 源代码网推荐 validationFieldElement.type = "hidden"; 源代码网推荐 validationFieldElement.name = "__EVENTVALIDATION"; 源代码网推荐 theForm.appendChild(validationFieldElement); 源代码网推荐 } 源代码网推荐 validationFieldElement.value = validationField; 源代码网推荐 } 源代码网推荐 if ((typeof(callbackObject.eventCallback) != "undefined") && (callbackObject.eventCallback != null)) { 源代码网推荐 callbackObject.eventCallback(response.substring(separatorIndex + validationFieldLength + 1), callbackObject.context); 源代码网推荐 } 源代码网推荐 } 源代码网推荐 } 源代码网推荐 } 源代码网推荐 } 源代码网推荐 源代码网推荐 //获取对应的回调对象 源代码网推荐 function WebForm_FillFirstAvailableSlot(array, element) { 源代码网推荐 var i; 源代码网推荐 for (i = 0; i < array.length; i++) { 源代码网推荐 if (!array[i]) break; 源代码网推荐 } 源代码网推荐 array[i] = element; 源代码网推荐 return i; 源代码网推荐 } 源代码网推荐 源代码网推荐 //再下面是一些辅助函数和与callback关系不大的函数,我就不列出来了,有兴趣的朋友可以自己看看 源代码网推荐 // 源代码网推荐 源代码网推荐 从以上代码我们可以很明白的看到,系统判断您的浏览器是否支持XMLHTTP或IFRAME,如果至少支持其中之一,则用相应的方法执行回调,否则当然就是提示错误了。回调的时候,采用post的方式,异步post到当前页面,然后等待回调结束,此时,由我们指定的返回数据处理script函数来处理返回的数据。 源代码网推荐 源代码网推荐 看到这里,我还不知道服务端怎么处理这个根据传过来的参数解析、执行,并返回数据的过程。但是,我们已经知道,WebForm_DoCallback(...)将会将当前页面的web控件的信息都post回去,这就意味着,我们在服务端有可能可以访问到这些web控件的value,这还不错,方便了我们处理当前数据。另一方面,eventArgument既然是一个任意格式的字符串参数,我们肯定要在服务段自己解析它的。 源代码网推荐 源代码网推荐 源代码网推荐 做人要厚道,请注明转自酷网动力(www.ASPCOOL.COM)。 源代码网推荐 源代码网供稿. |
