The implementation process is basically to implement the system on the page or space to implement the client callback function. web. UI. icallbackeventhandler interface, that is, two methods: void raisecallbackevent (string eventargument). This is the delegate method when the client triggers server events, string getcallbackresult (); this is the value required by the return client. It can only be string type. Of course, you can also return a JSON string.
Then register the script to the client during pageload: register a callserver method here to call the server method, and receiveserverdata to capture the results returned by the server. Of course, you can also use a method to capture server errors. For details, see the msdn explanation of page. clientscript. registerclientscriptblock.
In this way, the client can Callback Server events and return values.
After the page is generated, view the source code:
First, an additional JS resource file and a line of code is added:
At the end of the body, there is another code like this:
Webform_initcallback (); well, these should be the supplementary work that Asp.net has done to implement the client callback. Let's study it.
First look at the JS resource file (more than 20 K, sweat ...). Find this method in the resource file, webform_initcallback ();
The method is as follows:
1 function 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} This method is to load all the values in the form into a key-value pair.
Webform_initcallbackaddfield (element. Name, element. Value) is attached. method implementation:
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 );
}
}
When initializing the client callback function, Asp.net loads all the key-value pairs in the form into a global key-value pair.
Next, let's take a look at the work done by unction callserver (ARG, context) {webform_docallback ('_ page', ARG, receiveserverdata, context, null, false.
In the example, click the button to trigger the callserver method,
Function lookupstock ()
{
VaR lB = Document. getelementbyid ("listbox1 ");
VaR Product = LB. Options [lb. selectedindex]. text;
Callserver (product ,"");
}
Find the webform_docallback method in the resource file. Because the method is too long, only multipart Parsing is supported:
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 ){
}
} This Code adds some parameters to the postdata variable. And create an xmlrequest object. However, this method for creating asynchronous objects seems a bit inappropriate. He first checks whether it is a non-IE browser and then creates ActiveX objects only when cacth is in place, that is to say, I have to catch multiple times when IE is widely used. Why not save resources by placing ActiveX objects in front? No matter how much, let's look at the following:
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;
} The most important part of these statements is to assign the asynchronous callback method webform_callbackcomplete.
However, we ignored some details and let's start from scratch. There is a piece of code above
If (setrequestheadermethodexists)
That is to say, when the setrequestheadermethodexists variable is not null, an asynchronous object can be sent. How is this variable defined ??
VaR setrequestheadermethodexists = true;
Try {
Setrequestheadermethodexists = (xmlrequest & xmlrequest. setRequestHeader );
} That is to say, AJAX can be used only after the xmlrequest object is correctly created. What if Ajax objects cannot be correctly created? Check the code!
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 );
} Create an IFRAME! It turns out that AJAX can be used by all browsers.
The next step is to load some variables into the IFRAME and submit the IFRAME:
VaR interval = Window. setinterval (function (){
Xmlrequestframe = Document. Frames [callbackframeid];
If (xmlrequestframe & xmlrequestframe.doc ument ){
Window. clearinterval (interval );
Xmlrequestframe.doc ument. Write ("");
Xmlrequestframe.doc ument. Close ();
Xmlrequestframe.doc ument. Write ('
');
Xmlrequestframe.doc ument. Close ();
Xmlrequestframe.doc ument. 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.doc ument. createelement ("input ");
Fieldelement. type = "hidden ";
Fieldelement. Name = element. Name;
Fieldelement. value = element. value;
Xmlrequestframe.doc ument. Forms [0]. appendchild (fieldelement );
}
}
VaR callbackidfieldelement = xmlrequestframe.doc ument. createelement ("input ");
Callbackidfieldelement. type = "hidden ";
Callbackidfieldelement. Name = "_ callbackid ";
Callbackidfieldelement. value = eventtarget;
Xmlrequestframe.doc ument. Forms [0]. appendchild (callbackidfieldelement );
VaR callbackparamfieldelement = xmlrequestframe.doc ument. createelement ("input ");
Callbackparamfieldelement. type = "hidden ";
Callbackparamfieldelement. Name = "_ callbackparam ";
Callbackparamfieldelement. value = eventargument;
Xmlrequestframe.doc ument. Forms [0]. appendchild (callbackparamfieldelement );
If (theform ["_ eventvalidation"]) {
VaR callbackvalidationfieldelement = xmlrequestframe.doc ument. createelement ("input ");
Callbackvalidationfieldelement. type = "hidden ";
Callbackvalidationfieldelement. Name = "_ eventvalidation ";
Callbackvalidationfieldelement. value = theform ["_ eventvalidation"]. value;
Xmlrequestframe.doc ument. Forms [0]. appendchild (callbackvalidationfieldelement );
}
VaR callbackindexfieldelement = xmlrequestframe.doc ument. createelement ("input ");
Callbackindexfieldelement. type = "hidden ";
Callbackindexfieldelement. Name = "_ callbackindex ";
Callbackindexfieldelement. value = callbackindex;
Xmlrequestframe.doc ument. Forms [0]. appendchild (callbackindexfieldelement );
Xmlrequestframe.doc ument. Forms [0]. Submit ();
}
}, 10 );
}
The original method for initializing the client callback was to initialize all the form values to another IFRAME when the Ajax object could not be correctly created.
All right, the entire Asp.net client callback request sending is analyzed