ASP.NET 2.0 - Client/Server Javascript Postbacks in Final

ASP.NET 2.0 - Client/Server Callbacks

Those of you familiar with web development will probably know about the fabulous advantages of using Client/Server callbacks for retrieving information with doing a complete round trip to the server.   This is especially useful when performing lookups based on user entry.  There have been various incarnations that have demonstrated different ways to accomplish this such as hidden IFRAMEs, and the XMLHTTP ActiveX object.

You may be familiar with AJAX; a crossplatform implementation that uses the ActiveX object and is extremely powerful.  There are however situations in which AJAX may be overkill.

After googling for awhile looking for a good and more importantly current implementation of Client/Server postbacks in ASP.NET 2.0 it was apparent to me that there isn't a lot of good documentation out there on the subject.  There were some good articles, but most of the were based on an older version of the ICallbackEventHandler interface than is currently shipping with the release version of .NET.

Thus, I have created this simple explanation of how to implement this great new functionality.

Essentials: What's required?

Visual Studio 2005 / Visual Web Developer based on version 2.0.50727 of the .NET Framework

Step By Step:

1. Create a new web site.

Click File->New->Web Site or File->New Web Site.
Select ASP.NET Web Site
Name your project, and Click Ok.

2. Locate the CodeFile (previously CodeBehind) for the Default.aspx Web Form.  It is normally hidden or "Nested" below the Default.aspx file.  Once you have opened it, you should see something similar to the following code listing:

1: using System;
2: using System.Data;
3: using System.Configuration;
4: using System.Collections;
5: using System.Web;
6: using System.Web.Security;
7: using System.Web.UI;
8: using System.Web.UI.WebControls;
9: using System.Web.UI.WebControls.WebParts;
10: using System.Web.UI.HtmlControls;
11:  
12: public partial class _Default : System.Web.UI.Page
13: {
14:     protected void Page_Load(object sender, EventArgs e)
15:     {
16:  
17:     }
18: }

3. The first thing that we want to do inside Default.aspx.cs, is to implement the ICallbackEventHandler interface.  Lets modify our code on line 12 as follows:

12: public partial class _Default : System.Web.UI.Page,ICallbackEventHandler

As you can see we've added ICallbackEventHandler.  Next, we will add our implementation. 

4. Right click the ICallbackEventHandler portion of line 12, and click Implement Interface.  Doing so will add the following code to the code window:

19:     #region ICallbackEventHandler Members
20:  
21:     public string GetCallbackResult()
22:     {
23:         throw new Exception("The method or operation is
not implemented.");
24:     }
25:  
26:     public void RaiseCallbackEvent(string eventArgument)
27:     {
28:         throw new Exception("The method or operation is
not implemented.");
29:     }
30:  
31:     #endregion

(Your line numbers should match, but if they aren't the same, don't worry about it.)

As you can see, we have a default implementation of the ICallbackEventHandler now in place.  Lets remove the default exceptions for the body of each method.

19: #region
ICallbackEventHandler Members
20:  
21: public
string GetCallbackResult()
22: {
23: }
24:  
25: public
void RaiseCallbackEvent(string
eventArgument)
26: {
27: }
28:  
29: #endregion

Lets go ahead and save our work.  Ctrl-S for those of you who prefer the keyboard, File->Save for those who are mouse-bound.

5. Next, we will be editing our Default.aspx file.  Open this file and place yourself in source or markup view.    Here's what I have:

1: <%@ Page Language="C#"
AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default"
%>
2:  
3: <!DOCTYPE html PUBLIC "-//W3C//DTD
XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4:  
5: <html xmlns="http://www.w3.org/1999/xhtml" >
6: <head runat="server">
7:     <title>Untitled Page</title>
8: </head>
9: <body>
10:     <form id="form1" runat="server">
11:     <div>
12:     
13:     </div>
14:     </form>
15: </body>
16: </html>

Lets add a script block that to the <head> section as follows:

6: <head runat="server">
7:     <title>Untitled Page</title>
8:     <script type="text/javascript" language="javascript">
9:     function OutgoingMethod_ServerTime()
10:     {
11:         // Set our argument so
that the server side knows where
12:         // this request came from
13:         arg = "Time";
14:         <%=ScriptCallBackEventReference %>
15:     }
16:     function OutgoingMethod_IpAddressQuery()
17:     {
18:         // Set our argument so
that the server side knows where
19:         // this request came from
20:         arg = "IpAddress";
21:         <%=ScriptCallBackEventReference %>
22:     }
23:     
24:     function IncomingCallbackMethod(retvalue)
25:     {
26:         // Display our results
27:         obj = document.getElementById(
"resultDiv");
28:         obj.innerHTML = retvalue;
29:     }
30:     </script>
31: </head>

As you can see, we have added three methods.  The two methods labeled OutgoingMethod_ServerTime and OutgoingMethod_IpAddressQuery make use of a server side property called ScriptCallBackEventReference which we will create.  But first, lets create some supporting elements in Default.aspx.  Add code to the <body> section so that the entire body looks something like this:

1: <body>
2:     <form id="form1" runat="server">
3:     <div onclick="OutgoingMethod_ServerTime();" style="border:1px solid #AAAAAA;width:160px">
4:     Click here for server time    
5:     </div>
6:     <div onclick="OutgoingMethod_IpAddressQuery();" style="border:1px solid #AAAAAA;width:185px">
7:     Click here for your ip address
8:     </div>
9:     <div id="resultDiv">
10:     </div>
11:     </form>
12: </body>

Once you have the body code in place, switch back to code view in Default.aspx.cs.

We will now implement the ScriptCallBackEventReference property.  Add the following code:

18:     public string ScriptCallBackEventReference
19:     {
20:         get
21:         {
22:             return Page.ClientScript.GetCallbackEventReference(this, "arg", "IncomingCallbackMethod", null, false);
23:         }
24:     }

The Page.ClientScript.GetCallbackEventReference's overload shown here parameters are as follows:

  1. The control on the server-side that will handle the callback.  In this case, we use the page to handle it. 
  2. The client side argument to pass to the javscript callback function.  This is actually placed in the javascript code as you enter it without the quotes.  Therefore, you must create this argument on the javascript side.  This argument is then passed back to the server side method that handles the callback.
  3. The javascript function that will be called at the END of the request.
  4. An argument that will be evaluated client side before calling the method.
  5. Whether to perform this request asynchronously.

Next we are going to actually implement the ICallbackEventHandler methods.  Our two javascript methods are named OutgoingMethod_ServerTime and OutgoingMethod_IpAddressQuery respectively.  So will implement the functionality to return the appropriate result.

Inside the #region ICallbackEventHandler Members region.  Lets modify our GetCallbackResult method to look like this:

1: using System;
2: using System.Data;
3: using System.Configuration;
4: using System.Collections;
5: using System.Web;
6: using System.Web.Security;
7: using System.Web.UI;
8: using System.Web.UI.WebControls;
9: using System.Web.UI.WebControls.WebParts;
10: using System.Web.UI.HtmlControls;
11:  
12: public partial class _Default : System.Web.UI.Page,ICallbackEventHandler
13: {
14:     protected void Page_Load(object sender, EventArgs e)
15:     {
16:         
17:     }
18:     public string ScriptCallBackEventReference
19:     {
20:         get
21:         {
22:             return Page.ClientScript.GetCallbackEventReference(this, "arg", "IncomingCallbackMethod", null, false);
23:         }
24:     }
25:  
26:     #region ICallbackEventHandler Members
27:  
28:     string ret = string.Empty;
29:     public string GetCallbackResult()
30:     {
31:         return ret;
32:     }

Simply put, we are creating a variable in which we store our result, and inside GetCallbackResult, we return it.  The next step is to actually populate the variable with something interesting.  This happens in RaiseCallbackEvent.   Lets add our functionality to RaiseCallbackEvent.

 

34:     public void RaiseCallbackEvent(string eventArgument)
35:     {
36:         switch (eventArgument.ToLower())
37:         {
38:             case "time" :
39:                 ret = DateTime.Now.ToString();
40:                 break;
41:             case "ipaddress" :
42:                 ret = Request.ServerVariables["REMOTE_ADDR"];
43:                 break;
44:         }
45:     }
 We the variable that we are returning from GetCallbackResult with the appropriate data, and .NET Takes care of the rest.