“Atlas” Foundations: ASP.NET 2.0 Callback

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

One of the issues developers had when they first started to develop commercial Web sites was some of the limitations of using a browser as the interface. For instance, there were many cases where you wanted to retrieve information from the server after the user had performed some action, like entering an employee number in a Web page to retrieve the details of an employee. To accomplish this, you would post the current page to the server, retrieve the employee information from the database and refresh the page with the information retrieved from the server. Although this method of refreshing the whole page is very common today, it is inefficient because the Web page refreshes and re-renders the entire page of content, even if only a small percentage of the page has actually changed.

Fortunately ASP.NET 2.0 provides an efficient approach to invoke a remote function from a server page without refreshing the browser. This new feature is called ASP.NET 2.0 Script Callback, and it builds on the foundation of the XmlHttp object library. Using ASP.NET 2.0 script callback feature, you can emulate some of the behaviors of a traditional fat-client application in a Web-based application. It can be used to refresh individual controls, to validate controls, or even to process a form without having to post the whole page to the server. When you utilize script callback approach to retrieve data, you would typically transfer the data in the form of XML stream from the server side to the client and then load the XML data in a client-side XML DOM object to process the XML. In order to understand Microsoft’s “Atlas” which provides an easier way to build these “Ajax” style applications in ASP.NET 2.0, it’s useful to have a strong understanding of ASP.NET 2.0 Callback.

This article will consider an example wherein you retrieve the details of an employee based on the employee number entered in the Web page. To accomplish this, you will leverage the script callback feature and demonstrate how to retrieve the employee details from the AdventureWorks database (that ships with SQL Server 2005) without posting the page back to the server.

Before looking at the example, it is time to examine the steps involved in utilizing the callback feature.

  • The client invokes a client-side method that will use the callback manager.
  • The callback manager creates the request to a .aspx page on the server.
  • The ASP.NET runtime on the server receives the request, processes the request by invoking a predefined sever-side function named RaiseCallbackEvent and passing in the client side argument to it. The RaiseCallbackEvent method stores the client-side arguments in a private variable for later use. After that, the ASP.NET invokes another method named GetCallbackResult(), which is responsible for returning the output of the server-side call to the client-side callback manager.
  • The callback manager receives the server response and invokes a callback method located on the client-side. If there is an error during the server-side processing, the callback manager invokes a separate callback method.
  • The client callback method processes the results of the server-side call.

Now that you have understood the steps, Listing 1 shows an example page that implements callback feature.

Listing 1: Retrieving XML Data Dynamically Using ASP.NET 2.0 Script Callback

<%@ Page language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Import Namespace="System.Xml" %>
<%@ Import Namespace="System.Web.Configuration" %>
<%@ implements interface="System.Web.UI.ICallbackEventHandler" %>

<script runat="server">
  private string _callbackArg;
  void ICallbackEventHandler.RaiseCallbackEvent(string eventArgument)
  {
    _callbackArg = eventArgument;
  }

  string ICallbackEventHandler.GetCallbackResult()
  {
    try
    {
      int value = Int32.Parse(_callbackArg);
      return GetEmployeeDetails(value);
    }
    catch (Exception ex)
    {
      throw new ApplicationException
        ("An Error has occurred during the processing " +
        " of your request. Error is :" + ex.Message);
    }
  }

   public string GetEmployeeDetails(int employeeID)
   {
     string connString = WebConfigurationManager.
       ConnectionStrings["adventureWorks"].ConnectionString;
     try
     {
       using(SqlConnection sqlConnection = new SqlConnection(connString))
       {
         DataSet employeeDataset = new DataSet("EmployeesRoot");
         //Pass in the name of the stored
		 //procedure to be executed and the
         //SqlConnection object as the argument
         SqlDataAdapter adapter = new SqlDataAdapter();
         SqlCommand command =
		 	new SqlCommand("Select EmployeeID, Title, "+
           "CAST(HireDate AS char(12)) AS HireDate, Gender, " +
           "CAST(BirthDate AS char(12)) AS BirthDate from " +
           "HumanResources.Employee
		   	Where EmployeeID =" + employeeID.ToString(),
           sqlConnection);
         //Set the SqlCommand object properties
         command.CommandType = CommandType.Text;
         adapter.SelectCommand = command;
         //Fill the Dataset with the
		 //return value from the stored procedure
         adapter.Fill(employeeDataset,"Employees" );
         XmlDocument xmlDoc = new XmlDocument();
         return employeeDataset.GetXml();
       }
     }
     catch (Exception ex)
     {
       throw ex;
     }
   }

   public void Page_Load(object sender, EventArgs e)
   {
     if (!Request.Browser.SupportsCallback)
       throw new ApplicationException("This browser doesn't support " +
       "Client callbacks.");
     string src = Page.ClientScript.GetCallbackEventReference(this,
       "arg", "DisplayResultsCallback", "ctx",
	   "DisplayErrorCallback", false);
     string mainSrc = @"function
	 GetEmployeeDetailsUsingPostback(arg, ctx){ " +
	        src + "; }";
     Page.ClientScript.RegisterClientScriptBlock(this.GetType(),
       "GetEmployeeDetailsUsingPostback", mainSrc, true);
   }
</script>
<html>
<head>
  <title>Retrieving XML Dynamically
  using ASP.NET 2.0 Script Callback</title>
  <script language="javascript">
    function GetEmployeeDetails()
    {
      var n = document.forms[0].txtEmployeeID.value;
      GetEmployeeDetailsUsingPostback(n, "txtNumber");
    }

    function DisplayResultsCallback( result, context )
    {
      var strXML,objXMLNode,objXMLDoc,objEmployee,strHTML;
      objXMLDoc = new ActiveXObject("Microsoft.XMLDOM");
      //Load the returned XML string into XMLDOM Object
      objXMLDoc.loadXML(result);
      //Get reference to the Employees Node
      objEmployee = objXMLDoc.selectSingleNode("EmployeesRoot").
        selectSingleNode("Employees");
      //Check if a valid employee
	  //reference is returned from the server
      strHTML = "<font color='#0000FF'>";
      if (objEmployee != null)
      {
        //Dynamically generate HTML and append the contents
        strHTML += "<br><br>Employee ID :<b>" +
          objEmployee.selectSingleNode("EmployeeID").text
		  	 + "</b><br><br>";
        strHTML += "Title:<b>" +
          objEmployee.selectSingleNode("Title").text
		  	+ "</b><br><br>";
        strHTML += "Hire Date :<b>" +
          objEmployee.selectSingleNode("HireDate").text
		  	+ "</b><br><br>";
        strHTML += "Gender:<b>" +
          objEmployee.selectSingleNode("Gender").text
		  	+ "</b><br><br>";
        strHTML += "Birth Date:<b>" +
          objEmployee.selectSingleNode("BirthDate").text
		  	+ "</b><br><br>";
      }
      else
      {
        strHTML += "<br><br><b>Employee not found</b>";
      }
      strHTML += "</font>"
      //Assign the dynamically generated HTML into the div tag
      divContents.innerHTML = strHTML;
    }

    function DisplayErrorCallback( error, context )
    {
      alert("Employee Query Failed. " + error);
    }
  </script>

</head>
<body>
  <form id="Form1" runat="server">
    <font color="#800080"><H1>Employee Details</H1></font>
    <br><br>

    <P align="left">
      <font color="#800080"><b>Enter the Employee ID:</b>
      </font>     
      <INPUT id="txtEmployeeID" name="txtEmployeeID"
        style="LEFT: 149px; TOP: 72px">
      <INPUT id="btnGetEmployee" type="button"
	  	value="Get Employee Details"
        name="btnGetEmployee" onclick="GetEmployeeDetails()">

    </P>
    <P></P>
    <div id="divContents">
    </div>
    <P></P>

  </form>
</body>
</html>

To understand the code better, consider the code listing as being made up of three different parts.

  • Implementing the server-side event for callback
  • Generating the client-side script for callback
  • Implementing client callback method

Start by looking at the server-side event for callback.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read