Click here to Skip to main content
Click here to Skip to main content

Improving Web Application User Experience using AJAX and ASP.NET

, 19 Sep 2005
Rate this:
Please Sign up or sign in to vote.
This article explains AJAX and shows a sample using ASP.NET demonstating how it can be used to improve user experience of our web applications

Introduction

There are often scenarios where we as web developers wish we could provide users the richness and responsiveness of desktop applications. With web applications fast catching up, and also replacing their desktop counterparts, it’s only natural for the users to expect better user experience from the web applications we develop.

All of us must have hated the page refresh when we selected a country and then the state drop-down filled based on the country. There are other scenarios such as when we entered the wrong ticket ID on a website and waited for the long submit to render back to our browser only to find out we entered the wrong number, probably a typo. Such dependent drop-downs and server side validations on the website can soon start frustrating the users and force them to look at other websites which do it all on no submit of the page, just like a desktop application did. With businesses fast competing with each other, selling their products on the web and attracting probable customers, the user experience starts taking a primary role.

Today, we will take a look at a typical scenario which will demonstrate how a web application can provide better user experience using a set of existing technologies working together, called AJAX. Okay, let us first define AJAX.

AJAX – Defined

AJAX stands for Asynchronous JavaScript and XML. AJAX is a term coined by Adaptive Path and is not a new technology. It is a combination of various technologies working in conjunction with each other to provide a rich user experience to web users. AJAX uses:

  • Presentation layer using standard technologies viz. HTML in addition to using the browser's DOM for dynamic presentation and interaction.
  • Browser's DOM capability for data exchange between tiers.
  • Information exchange amongst tiers using XMLHTTPRequest.
  • Client scripting [preferably JavaScript] for making this all work together.

Let us now try dissecting the term AJAX.

A – Asynchronous

This means that this model is different from the Request – Response model associated with conventional web applications. In a conventional web application, the amount of time that elapses between a Request being sent to the server and the Response rendered to the browser can not be essentially put to utilization. The user is working synchronously with the various layers of the application and has an idle time during submits/refreshes. In the AJAX programming model, we can communicate with the business logic and the database layers while the user can still use the browser for doing other controlled [this is up to us to allow what we could allow the user to do during this time] actions. On the whole, this decouples the backend layers and the presentation layer as far as the user is concerned. We may call this as being Apparently Asynchronous.

JAX – JavaScript & XML

This means the Response received from the business logic and the database layer would be represented using XML whose manipulation can be done using JavaScript. JavaScript would also be used for dynamic presentation on the webpage. XML being only a preferred way of communication, the returned Response can even be text which your client side script would understand.

The figure above shows how the XMLHttpRequest object takes the responsibility of providing a communication layer between the Web Server and the presentation layer, enabling asynchronous communication between the Web Server and the presentation layer.

AJAX brings with it various advantages we can put to our use in improving the user experience of our websites but at the same time, it also comes with a few disadvantages. Let’s take a look at both:

Advantages

  • Lesser Data – Lesser Traffic- The amount of data sent over the network can be reduced since we speak of only the data interchange in the form of XML in most of the cases using AJAX. Compare this to the traditional view-submit-wait-view approach where the presentation data has to be sent to the browser as part of the response. You can imagine the difference in the generated network traffic here.
  • Freedom from Page Refresh – The browser page need not be refreshed every time some data is required from the business logic layer. A classical example is the Country-State dependent drop-downs. The user experience is much better when the states dropdown is populated without the page being refreshed.

Disadvantages

  • The trips to & fro the web server should be reduced as much as possible. Frequent trips to the server with large amount of data can quickly eat up the network bandwidth while the user may not realize it.
  • Disabling client scripting on the browser would cause the scripts to stop executing. Thus, applications using AJAX should be capable of making an alternate functionality made available to the user.

Let us now take a look at the sample application:

The Sample Application

Employee-Territory [Northwind Database] dependent dropdown example

This application uses a pair Employee – Territory dropdown list. When an Employee is selected from the Employee dropdown, the corresponding territories are loaded into the Territory dropdown. This kind of usage of dependent dropdowns is very common in applications. Conventionally, we have been submitting the page using the OnChange server side event of the Employee dropdown and filling the Territory dropdown on a server side event. This causes a page refresh, and depending on the size of the form, may take a long time to reload. The whole of the presentation code has to be rendered to the browser once again, in addition to maintaining the viewstate and filling the form fields with their previous values. In this example, we will see how the same operation can be performed with AJAX. With AJAX, we will eliminate the page refresh and will see how much we save on the network traffic.

We will use the famous Northwind database which ships as a sample database with the SQL Server installation. We consider three tables, Employees, EmployeeTerritories, and Territories having a structure and related to each other as per the following diagram:

Northwind Database Tables

EmployeeTerritoryAjaxClient.aspx

The EmployeeTerritoryAjaxClient.aspx is the page that is loaded to the browser. Initially, when the page is loaded, the Employee dropdown is filled on the Page_Load server side event. The page will initially look like in figure below:

EmployeeTerritoryAjaxClient.aspx

The OnChange event of the Employee dropdown invokes the populateTerritory() client-side JavaScript function. We will take a look at this function along with the other helper functions in a later section in this article. Let us now take a look at the presentation code of the EmployeeTerritoryAjaxClient.aspx page.

 <form id="frmEmployee" method="post" runat="server">
   <table border="0" cellpadding="5" cellspacing="0" bgcolor="#ccffff" width="280">
    <tr>
     <th colspan="2">
      AJAX Drop Down Demo</th>
    </tr>
    <tr>
     <td>
      <asp:Label id="lblEmployee" runat="server">Select Employee</asp:Label>
     </td>
     <td>
      <asp:DropDownList id="ddEmployee" Runat="server"></asp:DropDownList>
     </td>
    </tr>
    <tr>
     <td>
      <asp:Label id="lblTerritory" runat="server">Select Territory</asp:Label>
     </td>
     <td>
      <asp:DropDownList id="ddTerritory" runat="server">
       <asp:listitem Value="">--Select--</asp:listitem>
      </asp:DropDownList>
     </td>
    </tr>
    <tr>
     <td colspan="2" align="center">
       <asp:Label id="lblStatus" runat="server" class="statustext"></asp:Label>
     </td>
    </tr>
   </table>
 </form>

Now, we will look at the code-behind C# code of this page.

EmployeeTerritoryAjaxClient.aspx.cs

  private void Page_Load(object sender, System.EventArgs e)
  {
   if(!IsPostBack)
   {
    string connString = ConfigurationSettings.AppSettings["CONN_STRING"];
    //Connect to the Northwind Database

    SqlConnection connection = new SqlConnection(connString);
    connection.Open();



    //Build the SQL Query
    string SQL = "SELECT EmployeeID, TitleOfCourtesy + ' ' + LastName + ', ' + 
                  FirstName as EmpName FROM Employees";
    SqlDataAdapter da = new SqlDataAdapter(SQL, connection);
    DataSet ds = new DataSet();
    da.Fill(ds);

    //Create a DataView with the DefaultView property of the DataSet table
    DataView dv = new DataView();
    dv = ds.Tables[0].DefaultView;

    //Call BindEmployee by passing the created DataView object
    BindEmployee(dv);
   }
  }

BindEmployee Method

  private void BindEmployee(DataView dv)
  {
   try
   {
    if(dv != null) //If DataView is not null
    {
     ddEmployee.DataSource = dv;
     //Text to display in Employee Dropdown
     ddEmployee.DataTextField = "EmpName";
     //Value to be associated in Employee Dropdown
     ddEmployee.DataValueField = "EmployeeID";
     ddEmployee.DataBind();
     ListItem item = new ListItem("--Select--", "");
     ddEmployee.Items.Insert(0, item);
    }
    else
    {
     throw new Exception("Dataview is null.");
    }
   }
   catch(Exception ex)
   {
    Response.Write("Exception: " + ex.Message);
   }
  }

InitializeComponent Method

  private void InitializeComponent()
  {    
   this.Load += new System.EventHandler(this.Page_Load);
   //Important: Add this statement below to invoke the populateTerritory() JavaScript
   this.ddEmployee.Attributes.Add("OnChange", "return populateTerritory();");
  }

The Page_Load code is straightforward. A connection to the database is established and records from the Employees table are populated to a dataset via a SqlDataAdapter. The DefaultView of the Employees table from the dataset is passed as a parameter to the BindEmployee() method. BindEmployee() populates the Employee dropdown on the page.

One thing to notice here is the following code of the InitializeComponent() method:

ddEmployee.Attributes.Add("OnChange", "return populateTerritory()"); 

where we add the OnChange event to the Employee dropdown. This OnChange event is the one which invokes the populateTerritory() JavaScript function which in turn invokes other helper functions. We will look at these JavaScript functions next.

JavaScript functions:

   <script language="javascript">
   var request;
   var response;
   var Territory = document.getElementById("ddTerritory");
   var status = document.getElementById("lblStatus");
   function populateTerritory()
   {
    var Employee = document.getElementById("ddEmployee");
    if(Employee.options[Employee.selectedIndex].value != '')
    //Check if the selectedItem is not "--Select--"
    {
     return SendRequest(Employee.options[Employee.selectedIndex].value);
    }
    else
    {
     clearSelect(Territory);//Clear the Territory dropdown
     status.innerText = "";//Blank the status text label
    }
   }
   function InitializeRequest()
   {
    try
    {
     request = new ActiveXObject("Microsoft.XMLHTTP");
     //Try creating an XMLHTTP Object
    }
    catch(Ex)
    {
     try
     {
      //First failure, try again creating an XMLHTTP Object
      request = new ActiveXObject("Microsoft.XMLHTTP");
     }
     catch(Ex)
     {
        //Else assign null to request

    request = null;
     }
    }
    if(!request&&typeof XMLHttpRequest != 'undefined')
    {
     request = new XMLHttpRequest();
    }
   }
   function SendRequest(ID)
   {
    status.innerText = "Loading.....";//Set the status to "Loading....."
    InitializeRequest();//Call InitializeRequest to set request object
    
    //Create the url to send the request to
    var url = "EmployeeTerritoryAjaxServer.aspx?EmployeeID="+ID;


    //Delegate ProcessRequest to onreadystatechange property so 
    //it gets called for every change in readyState value
    request.onreadystatechange = ProcessRequest;

    request.open("GET", url, true);//Open a GET request to the URL
    request.send(null);//Send the request with a null body.
   }
   function ProcessRequest()
   {
    if(request.readyState == 4)
    //If the readyState is in the "Ready" state
    {
     if(request.status == 200)
     //If the returned status code was 200. 
     //Everything was OK.
     {
      if(request.responseText != "")
      //If responseText is not blank
      {
       //Call the populateList fucntion
       populateList(request.responseText);
       //Set the status to "Territories Loaded"
       status.innerText = "Territories Loaded";
      }
      else
      {
       //Set the status to "None Found"
       status.innerText = "None Found";
       //Call clearSelect function
       clearSelect(Territory);
      }
     }
    }
    return true;//return
   }
   function populateList(response)
   {
    //Create the XMLDOM object
    var xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
    xmlDoc.async = false;
    //Load the responseText into the XMLDOM document
    xmlDoc.loadXML(response);
    var opt;
    //Create the EmployeeTerritories element
    var TerritoriesElem = 
      xmlDoc.getElementsByTagName("EmployeeTerritories"); 

    //Create the TERRITORIES element
    var TerritoryElem = 
      TerritoriesElem[0].getElementsByTagName("TERRITORIES");

    clearSelect(Territory);
    //Clear the dropdown before filling it with new values


    if(TerritoriesElem.length > 0)
    //If there are one or more TERRITORIES nodes
    {
    for (var i = 0; i < TerritoryElem.length; i++)
    //Loop through the XML TERRITORIES nodes
    {
     //Create a TextNode
     var textNode = document.createTextNode(
           TerritoryElem[i].getAttribute("TERRITORYDESCRIPTION"));
     //Call appendToSelect to append the text 
     //elements to the Territory dropdown
     appendToSelect(Territory, 
       TerritoryElem[i].getAttribute("TERRITORYID"), textNode);
    }
    }
   }
   function appendToSelect(select, value, content)
   {
    var opt;
    //Create an Element of type option
    opt = document.createElement("option");
    //Set the option's value
    opt.value = value;
    //Attach the text content to the option
    opt.appendChild(content);
    //Append the option to the referenced [Territory] select box
    select.appendChild(opt);
   }
   function clearSelect(select)
   {
    //Set the select box's length to 1 
    //so only "--Select--" is available in the selection on calling this function.
     select.options.length = 1;
    //You may want to write your own clearSelect logic
   }
   </script>

There are three JavaScript global variables: request, state, and status. request will contain the XMLHttpRequest object. state and status will contain the ddTerritory dropdown and lblStatus objects respectively. Now, let us see how the execution flows when an employee is selected:

  • The populateTerritory() function is invoked. This function in turn invokes the SendRequest() function conditionally by passing the selectedIndex value of the ddEmployee dropdown.
  • SendRequest() function invokes InitializeRequest which creates an XMLHttpRequest object named request.
  • SendRequest() also does the following operations:
    • It delegates the ProcessRequest() function to the request object's onreadystatechange event.
    • It opens a GET request to the EmployeeTerritoryAjaxServer.aspx page URL.
    • It sends a request to the page with a null argument. If you want to send the page values as part of a POST request, you can send those values using this parameter.
    • The ProcessRequest() function is of special interest to us. We determine the current state of the request using this function, and accordingly assign the functionality to other functions. There are the following five possible readyState values for the request object:

      readyState value

      Status

      0 Uninitialized
      1 Loading
      2 Loaded
      3 Interactive
      4 Completed
    • The ProcessRequest() function invokes the populateList() function with the response obtained from the EmployeeTerritoryAjaxServer.aspx page. This response is an XML stream which is parsed using a DOM parser and calling the appendToSelect() function which is self describing.

Let us now take a look at the EmployeeTerritoryAjaxServer.aspx page. This page essentially contains only the Page attribute tag and no HTML. We return the response from the page with the content-type of "text/xml".

Here is the code-behind C# code of the EmployeeTerritoryAjaxServer.aspx page:

EmployeeTerritoryAjaxServer.aspx.cs

  private void Page_Load(object sender, System.EventArgs e)
  {
   string ID = Request["EmployeeID"];
   
   if(ValidateID(ID))
   {
    if(ID.Trim() != "" && ID != null)
    {
     try
     {
      SqlConnection conn = new 
        SqlConnection(ConfigurationSettings.AppSettings["CONN_STRING"]);
      //Connect to the Northwind Database
      conn.Open();
      SqlCommand command = 
        new SqlCommand("SELECT TERRITORYID, RTrim(TERRITORYDESCRIPTION) as" + 
            "TERRITORYDESCRIPTION FROM TERRITORIES WHERE TERRITORYID IN" + 
            "(SELECT TERRITORYID FROM EMPLOYEETERRITORIES WHERE EMPLOYEEID=" 
            + ID + ") for xml auto", conn);
      //Execute the SqlCommand Object
      SqlDataReader dr = command.ExecuteReader();
      System.Text.StringBuilder sbXML = 
             new System.Text.StringBuilder();
      if(dr.HasRows)
      {
       while(dr.Read())
       {
        sbXML.Append(dr.GetString(0).Trim());
       }
       //Set the ContentType of the Response Object to "text/xml"
       Response.ContentType = "text/xml";
       //Response.Write the XML generated 
       //by appending <EmployeeTerritories> tag on 
       //both ends of the XML string to create a documentElement
       Response.Write("<EmployeeTerritories>" + 
             sbXML.ToString() + "</EmployeeTerritories>");
      }
      else
      {
       //Response.Write an empty string so your client script 
       //understands no response was returned
       Response.Write("");
      }
     }
     catch
     {
      //Response.Write an empty string so your client script 
      //understands no response was returned
      Response.Write("");
     }
    }
    else
    {
     //Response.Write an empty string so your client script 
     //understands no response was returned
     Response.Write("");
    }
   }
  }

Page_Load Event

The Page_Load event is straightforward. One thing to note here is that I am using the FOR XML AUTO option of SQL Server 2000 for getting the query results as XML. I append a <Territories> tag around this result XML and send the response back to the caller. If you are using a different data source that does not support automatic XML generation, you can build your own XML nodes and write the response.

ValidateID method

  private bool ValidateID(string ID)
  {
   for(int Count=0;Count<ID.Length;Count++)
   {
    if (!System.Char.IsNumber(ID, Count))
    //Check if the input ID value is numeric
    {
     return false;
    }
   }
   return true;
  }

The ValidateID() method validates the ID that is sent by the caller and returns a boolean value stating if it is valid or not.

Executing Sample Code

Before running the sample application, you will need to create a virtual directory of the AJAXDropDown folder inside the AJAX___ASPNET folder after unzipping. Also, make sure that you have an instance of SQL Server 2000 available and you have the Northwind database in that. Open the solution in Visual Studio and modify the following element in your web.config file.

<add key="CONN_STRING" value="data source=<your data source here >;
     Database=northwind;User=<user name>;PWD=<password>"/>

Build the application before running it.

Try selecting an employee, you will see the Territory dropdown filling with the corresponding territories as in the figure below:

Summary

In this article, we discussed about AJAX and how it can be used in a web application to improve user experience. We also saw how we saved on the amount of data being transmitted over the network by sending the response as XML and not the whole rendering HTML code. There are various such applications which can benefit by using AJAX. At the same time, it is up to us to decide where we want to make use of this concept depending on various factors viz., security, environment, performance etc.

I would like to thank my colleague Rashmi Ramachandra for making those diagrams you saw earlier in the article.

I hope this made an interesting reading for you. You can send me your comments at srinivas.alagarsamy@gmail.com. Thank you!!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Alagarsamy, Srinivas
Web Developer
United States United States
No Biography provided

Comments and Discussions

 
General'0' is Null or Not on Object Pinmemberganjimadhuker7-Mar-07 20:07 
GeneralRe: '0' is Null or Not on Object PinmemberTCruz In the House7-Jun-07 6:36 
GeneralRe: '0' is Null or Not on Object PinmemberRyanJay21-Jun-07 8:54 
GeneralRe: '0' is Null or Not on Object PinmemberTCruz In the House21-Jun-07 9:52 
Generalit is useless Pinmembersinhanu20-Feb-07 22:22 
GeneralRe: it is useless Pinmemberrujuc#14-May-07 23:02 
QuestionHow to convert this section for VB.NET PinmembernewException3-Jan-07 1:48 
GeneralError : 0 is null or not an object PinmemberMember #368397331-Dec-06 21:07 
Generalthanx Pinmemberkavitha.net15-Dec-06 19:55 
QuestionHow will we take the value and text of 2nd dropdownlisT? Pinmemberosmanayhan9-Nov-06 4:11 
AnswerRe: How will we take the value and text of 2nd dropdownlisT? Pinmemberduantv2-Mar-11 14:55 
GeneralAuto save using Ajax Pinmemberaavesh21-Aug-06 21:14 
GeneralWorks great Pinmember!nfinite818-Jul-06 10:24 
QuestionProblem with xmlDoc.loadXML(response); Pinmemberf.rivero@ibitech.com5-May-06 0:25 
GeneralProcessRequest function showing ReadyState 3 Pinmemberamit__827-Mar-06 0:26 
GeneralRe: ProcessRequest function showing ReadyState 3 PinmemberSrinivas Alagarsamy27-Mar-06 3:15 
GeneralRe: ProcessRequest function showing ReadyState 3 Pinmemberamit__827-Mar-06 17:41 
QuestionHow to make it work in Browsers other than IE PinmemberJohn2m23-Jan-06 2:41 
AnswerRe: How to make it work in Browsers other than IE PinmemberSrinivas Alagarsamy23-Jan-06 2:45 
GeneralRe: How to make it work in Browsers other than IE PinmemberJohn2m23-Jan-06 21:55 
I m new to web programming and weak in javascript code, Problem is this code isnt working in Firefox , since i guess its using ActiveXObject.How to make it work in Firefox .
GeneralRe: How to make it work in Browsers other than IE PinmemberJohn2m24-Jan-06 1:19 
GeneralRe: How to make it work in Browsers other than IE PinmemberSrinivas Alagarsamy24-Jan-06 2:30 
QuestionRe: How to make it work in Browsers other than IE PinmemberArunKKumar4-May-06 0:13 
JokeGood job Pinmemberabellix22-Dec-05 3:39 
GeneralRe: Good job Pinmemberprashudupa28-Mar-06 2:01 
GeneralWell done - good article Pinmemberjohnboy_endy10-Dec-05 5:49 
Questionnot Gettin values in second DropDownLIst Pinmembermbsum7-Dec-05 20:28 
AnswerRe: not Gettin values in second DropDownLIst PinmemberSrinivas Alagarsamy8-Dec-05 9:52 
Generalstate doesnt maintain Pinmembersreejin7-Dec-05 11:58 
GeneralRe: state doesnt maintain Pinmembervmf29-Jan-06 21:47 
GeneralRe: state doesnt maintain PinmemberSrinivas Alagarsamy17-Feb-06 4:26 
QuestionRe: state doesnt maintain Pinmemberamit__830-Mar-06 23:02 
QuestionRe: state doesnt maintain PinmemberStephen Noronha4-Apr-06 11:59 
AnswerRe: state doesnt maintain PinmemberSrinivas Alagarsamy4-Apr-06 12:54 
AnswerRe: state doesnt maintain PinmemberSrinivas Alagarsamy4-Apr-06 12:58 
GeneralRe: state doesnt maintain PinmemberStephen Noronha4-Apr-06 13:32 
GeneralRe: state doesnt maintain Pinmemberlilupatnaik8-Apr-06 19:56 
GeneralRe: state doesnt maintain PinmemberSrinivas Alagarsamy9-Apr-06 5:03 
GeneralGreat Article Pinsussdoodaa28-Sep-05 6:29 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 20 Sep 2005
Article Copyright 2005 by Alagarsamy, Srinivas
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid