Click here to Skip to main content
15,879,239 members
Articles / Web Development / HTML
Article

Improving Web Application User Experience using AJAX and ASP.NET

Rate me:
Please Sign up or sign in to vote.
3.74/5 (16 votes)
19 Sep 2005CPOL9 min read 150.9K   74   39
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.

Image 1

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:

Image 2

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:

Image 3

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.

HTML
<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

C#
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

C#
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

C#
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:

C#
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:

JavaScript
<script language="javascript">
var request;
var response;
var Territory = document.getElementById("ddTerritory");
var status = document.getElementById("lblStatus");
JavaScript
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
 }
}
JavaScript
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();
 }
}
JavaScript
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.
}
JavaScript
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
}
JavaScript
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);
 }
 }
}
JavaScript
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);
}
JavaScript
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

      0Uninitialized
      1Loading
      2Loaded
      3Interactive
      4Completed
    • 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

C#
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

C#
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.

XML
<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:

Image 4

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)


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
General'0' is Null or Not on Object Pin
ganjimadhuker7-Mar-07 20:07
ganjimadhuker7-Mar-07 20:07 
GeneralRe: '0' is Null or Not on Object Pin
TCruz In the House7-Jun-07 6:36
TCruz In the House7-Jun-07 6:36 
GeneralRe: '0' is Null or Not on Object Pin
RyanJay21-Jun-07 8:54
RyanJay21-Jun-07 8:54 
GeneralRe: '0' is Null or Not on Object Pin
TCruz In the House21-Jun-07 9:52
TCruz In the House21-Jun-07 9:52 
Generalit is useless Pin
sinhanu20-Feb-07 22:22
sinhanu20-Feb-07 22:22 
GeneralRe: it is useless Pin
rujuc#14-May-07 23:02
rujuc#14-May-07 23:02 
QuestionHow to convert this section for VB.NET Pin
newException3-Jan-07 1:48
newException3-Jan-07 1:48 
GeneralError : 0 is null or not an object Pin
amit.khurana@migital.com31-Dec-06 21:07
amit.khurana@migital.com31-Dec-06 21:07 
Generalthanx Pin
kavitha.net15-Dec-06 19:55
kavitha.net15-Dec-06 19:55 
QuestionHow will we take the value and text of 2nd dropdownlisT? Pin
osmanayhan9-Nov-06 4:11
osmanayhan9-Nov-06 4:11 
AnswerRe: How will we take the value and text of 2nd dropdownlisT? Pin
duantv2-Mar-11 14:55
duantv2-Mar-11 14:55 
GeneralAuto save using Ajax Pin
Amit Agarrwal21-Aug-06 21:14
Amit Agarrwal21-Aug-06 21:14 
GeneralWorks great Pin
!nfinite818-Jul-06 10:24
!nfinite818-Jul-06 10:24 
QuestionProblem with xmlDoc.loadXML(response); Pin
f.rivero@ibitech.com5-May-06 0:25
f.rivero@ibitech.com5-May-06 0:25 
GeneralProcessRequest function showing ReadyState 3 Pin
amit__827-Mar-06 0:26
amit__827-Mar-06 0:26 
GeneralRe: ProcessRequest function showing ReadyState 3 Pin
Alagarsamy, Srinivas27-Mar-06 3:15
Alagarsamy, Srinivas27-Mar-06 3:15 
Can you send the code that shows this behavior. I will try to take a look and revert ASAP.

Regards

Sri
GeneralRe: ProcessRequest function showing ReadyState 3 Pin
amit__827-Mar-06 17:41
amit__827-Mar-06 17:41 
QuestionHow to make it work in Browsers other than IE Pin
John2m23-Jan-06 2:41
John2m23-Jan-06 2:41 
AnswerRe: How to make it work in Browsers other than IE Pin
Alagarsamy, Srinivas23-Jan-06 2:45
Alagarsamy, Srinivas23-Jan-06 2:45 
GeneralRe: How to make it work in Browsers other than IE Pin
John2m23-Jan-06 21:55
John2m23-Jan-06 21:55 
GeneralRe: How to make it work in Browsers other than IE Pin
John2m24-Jan-06 1:19
John2m24-Jan-06 1:19 
GeneralRe: How to make it work in Browsers other than IE Pin
Alagarsamy, Srinivas24-Jan-06 2:30
Alagarsamy, Srinivas24-Jan-06 2:30 
QuestionRe: How to make it work in Browsers other than IE Pin
ArunKKumar4-May-06 0:13
ArunKKumar4-May-06 0:13 
JokeGood job Pin
abellix22-Dec-05 3:39
abellix22-Dec-05 3:39 
GeneralRe: Good job Pin
prashudupa28-Mar-06 2:01
prashudupa28-Mar-06 2:01 

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

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