Background
Asynchronous JavaScript and XML or AJAX has been the revolutionary technology that enabled rich user experience over the web, much like the desktop rich user experience. In this series, I will describe my journey of learning AJAX and some simple steps that will get you started with this simple but powerful technology.
Introduction
AJAX enables web developers to dynamically update a web page via background asynchronous posts to the server. Hence it removes the necessity of sending an entire page back to the server and cause a global refresh in the browser. This results in the following major benefits:
- Rich user experience – a web user doesn’t have to wait until the entire page is loaded. Nor is he / she distracted by visual information loss during the page reloads. AJAX also can be used to display progress information while a sub-portion of the page is being updated / loaded from the server.
- Server scalability – Since only minimal information is exchanged between the client and the server, the server can serve more clients in turn with the same amount of resources (memory, CPU). This helps in increasing server scalability.
- Client efficiency – The client browser only needs to update a sub-portion of an already loaded web page as opposed to parsing and displaying the entire page all over again.
Figure 1 – Classic Web Application Model
Figure 2 – AJAX Web Application Model
The solid lines depict synchronous operations whereas the gray lines depict asynchronous operations.
Building Blocks of AJAX
AJAX is not a technology by itself. It is an outcome of several collaborating technologies that fit their respective roles in the overall end to end asynchronous HTTP request / response process. The major building blocks involved in the AJAX web application model are:
- Standards based presentation using XHTML and CSS.
- DHTML – Browser capabilities to manipulate the XML Document Object Model (DOM) for the loaded web page.
- JavaScript – Base language technology for performing all client-side activities during AJAX operations. A client browser must have support for JavaScript in order to support AJAX operations. Many vendors have to support both AJAX style web pages (for desktop browsers) as well as traditional post-back web pages (for mobile device browsers) to capture the entire spectrum of users.
XMLHttpRequest
object – A browser must support the XMLHttpRequest
JavaScript object for initiating asynchronous web requests. Different browsers have different ways to retrieve this object. There are many documented shims available that explain how to retrieve this object. Here is an example from Wikipedia:
if (typeof(XMLHttpRequest) == "undefined") {
XMLHttpRequest =
function(){
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch(e) {}
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch(e) {}
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch(e) {}
try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch(e) {}
throw new Error("This browser does not support XMLHttpRequest.");
};
}
This example shows how to add a shim type of the same name XMLHttpRequest
if the browser doesn’t support it out of the box. For a complete reference on the XMLHttpRequest
JavaScript class, refer to the Mozilla Developer Center page.
I highly recommend reading a book that explains the above technologies in depth to get your basics right. I personally read Beginning AJAX with ASP.NET and found it a very good start for beginners. However, later chapters in the book are outdated as technologies that they mention, especially Microsoft Atlas, have considerably changed since the book was released.
First AJAX Experience
In the beginning of this article, I promised to present AJAX in a very approachable style. For years, I had ignored learning this technology as I considered it to be very non-standard and hacky then. Now, I differ in my opinion owing to the fact that there are many technologies in the AJAX web model that have been recognized as industry standards and are now W3C compliant. Anyways, let’s now see things in action! Create an ASP.NET web application in Visual Studio where you will test your first AJAX code. Then, create an XML file, note.xml, in the project and overwrite its contents with the following:
="1.0"="iso-8859-1"
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this
weekend!</body>
</note>
Next, create an HTML document in the project, ajax.htm, with the following content:
<html>
<head><title>First AJAX
Example</title></head>
<script type="text/javascript">
var request;
var READYSTATE_COMPLETE = 4;
if (typeof(XMLHttpRequest) == "undefined") {
XMLHttpRequest =
function() {
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch(e) {}
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch(e) {}
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch(e) {}
try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch(e) {}
throw new Error("This browser does not support XMLHttpRequest.");
};
}
function ReadXmlFile() {
request = new XMLHttpRequest();
request.open('GET', 'note.xml', true);
request.onreadystatechange = DisplayXmlFile;
request.send(null);
}
function DisplayXmlFile() {
if (request.readyState == READYSTATE_COMPLETE) {
xmlSpan.innerText = request.responseText;
}
}
</script>
<body>
<span id="xmlSpan"></span><input
type="button" onclick="ReadXmlFile();" value="ReadXml" />
</body>
</html>
Finally, fire the app in the browser and open ajax.htm. You will see if you hit the ReadXml button, the xmlSpan
span gets populated with the contents of note.xml without refreshing the page, as shown in Figure 3 below.
Figure 3 – Running the first AJAX example
Security Note
In order to ensure online security and prevent cross scripting attacks, browsers limit the XMLHttpRequest
object to only request resources from the same domain as the domain of the web application. You can verify this in the above example. Instead of requesting note.xml, try requesting http://www.w3schools.com/XML/note.xml which has the same content. Running the application will not allow the XML file to be fetched. Replace it again with note.xml and it will work again.
AJAX Frameworks
In recent years, the use of AJAX in major web portals has revolutionized online user experience. Although Microsoft was the first company to make use of AJAX, it was Google which truly captured the power of this technology and set a new standard for online user experience. Several frameworks have been built to increase developer productivity while developing AJAX based web applications. These frameworks can be categorized into the following major categories:
- Client side frameworks – JavaScript libraries/frameworks that help developers reuse/leverage client side JavaScript code.
- Server side frameworks – Server side code generators/injectors combined with capabilities to extend client side AJAX JavaScript code to achieve extensibility and reusability in AJAX web application development.
Each of the categories has their own benefits and drawbacks. The decision to pick one over the other depends on the nature of the application being developed and the platforms being used to develop those applications. A lot of time, developers also pick a combination of tools belonging to different categories and integrate them together to achieve the desired end product. I will walk you through an example of each of the following categories in the upcoming sections.
Client Side Frameworks
Many efforts have been made to enhance JavaScript to support AJAX via reusable libraries. Quite possibly, the biggest effort is the conception of jQuery – a lightweight library that emphasizes interaction between JavaScript and HTML. Microsoft has already adopted this framework which is now shipping with the ASP.NET MVC Framework, and in the near future will be a part of the upcoming Visual Studio 2010 release. Let us rewrite our previous example using jQuery. Again, follow the previous example as is, except this time, your HTML page should have the following content:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>AJAX with jQuery</title>
</head>
<script src="Scripts/jquery-1.3.2.js"
type="text/javascript"></script>
<script
type="text/javascript">
$(document).ready(function() {
$("#ReadButton").click(function() {
$.ajax({
type: "GET",
url: "note.xml",
success: function(msg) {
$("#xmlSpan").attr("innerText", msg.xml);
}
});
});
});
</script>
<body>
<span id="xmlSpan"></span><input type="button" id="ReadButton"
value="ReadXml" />
</body>
</html>
The script to fetch note.xml this time is so much more concise! Also, note that we didn’t need to do anything funky on the server side to make it work. We didn’t have to create XMLHttpRequest
object and check for the browser type while doing so. Also, we didn’t have to declare constants to check the states for the XMLHttpRequest
object. Just a precise subscription to the success event got our callback going!
OK, you must be wondering: well, the above works well, but what if HTTP POST is required instead of a GET, and how does one go about executing business logic on the backend while making asynchronous HTTP POST requests. Well, the answer is simple. We can use the POST version of the jQuery AJAX call to achieve the same. We shall see this approach in the scenario below.
Consider that you want to call a method GetPerson
on your backend ASP.NET page that gives you a custom Person
object. Let’s assume that this Person
object is to be processed on the client and displayed to the user. Let’s see how we can go about doing it.
In order to achieve the above scenario, we must understand how serialization works between a backend .NET managed object and JavaScript objects. Any object in JavaScript can be serialized to JSON (JavaScript Object Notation) format. As well as any JSON object can be deserialized into a JavaScript object. JSON is really a format for structured data interchange between systems. The BNF for object denotation in JSON is as follows:
JSON Notation := { } | {KeyValuePair}
KeyValuePair := Key : Value | KeyValuePair, Key : Value
Key := String
Value := String | Number | JSON Notation | Array | true | false | null
Array := [ ] | [Value] | [Value, Value]
Hence, if you have a Person
object storing FirstName
and LastName
, then the following can be a JSON representation of a Person
instance:
{PersonInstance: {FirstName:John, LastName:Rambo}}
and an array of Person
objects can be represented as:
{PersonList: [{FirstName:John, LastName:Rambo}, {FirstName:Austin, LastName:Powers}]}
The format of JSON closely matches how JavaScript interprets its objects, i.e., in the form of nested key value pairs. Yes, everything in JavaScript, properties, methods, events, are just key value pairs of some sort, and hence JavaScript objects are nothing but nested dictionaries! If you follow the persistence format of many other vendors, this is usually a strikingly common way of representing objects. (Apple also uses a similar plist format to store property lists in MacOS and also in iTunes! For more information about plist, check out its Wikipedia page.)
Anyhow, back to our GetPerson example. We will create a simple ASP.NET page with the following code-behind:
using System;
using System.Web.Services;
[Serializable]
public class Person
{
public string FirstName
{get;set;}
public string LastName {get;set;}
}
public partial class Person_Page : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
[WebMethod]
public static Person GetPerson(Person person)
{
return new Person { FirstName = person.FirstName, LastName = person.LastName };
}
}
There is one static web method called GetPerson
that accepts a parameter of type Person
. Person
really contains the first name and the last name of a person. GetPerson
then simply returns a new Person
object with the same first and last name. One important thing to note is that the Person
object is marked with a Serializable
attribute. In CLR, if an object is marked with a Serializable
attribute, then it can be serialized into any given format / and or built from any format back as an object. Also note the public static
visibility type and the WebMethod
attribute on the GetPerson
method. This is essential to expose a method to be called by client web requests. We shall see how we can call this method from the client code below:
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="Person_Page.aspx.cs" Inherits="Person_Page" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>jQuery POST
Example</title>
</head>
<script
src="Scripts/jquery-1.3.2.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#GetPerson").click(function() {
var firstname = $("#txtFirstName").val();
var lastname = $("#txtLastName").val();
content = "{'person':{'FirstName':'" + firstname +
"', 'LastName':'" + lastname + "'}}";
$.ajax({
type: "POST",
url: "Person_Page.aspx/GetPerson",
data: content,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg)
{
var fullName = msg.d.LastName + ", " + msg.d.FirstName;
$("#lblFullName").text(fullName);
}
});
});
});
</script>
<body>
<form id="form1" runat="server">
<div>
First Name: <input type="text" id="txtFirstName" />
Last Name: <input type="text" id="txtLastName" />
<br />
<input type="button" id="GetPerson" value="GetPerson"></input>
<span id = "lblFullName"></span>
</div>
</form>
</body>
</html>
We have two text fields here, txtFirstName
and txtLastName
, that capture the first and the last name of the person, respectively. Then, we have a GetPerson button that makes the AJAX call to the code-behind of the page and tries to call a web method GetPerson
and passes in the constructed JSON from the txtFirstName
and txtLastName
fields via a content string variable. Once the response is received back from the server, the text of the span lblFullName
is updated to show the full name in the format LastName, FirstName. Following is the screenshot while running the above code:
Figure 4 – jQuery POST example in action
As can be seen, when the CLR receives the POST requests, it queries the HTTP ContentType
field value. Since it is specified as application / json, it deserializes the Person
object from JSON to the actual Person
instance and also serializes the resulting Person
object from GetPerson
back to JSON. Also notice the JSON string construction from the client script in the content string object. We specify the key of the object to be ‘person’ which is the same name as the formal parameter name of the Person
object in the GetPerson
web method. This allows for binding of parameters during the call so values can be passed correctly to the web method.
Server Side Frameworks
Server side frameworks dynamically generate and inject AJAX JavaScript snippets into server processed forms, so developers are not bothered with writing JavaScript every time they desire AJAX style functionality in their web applications. We already have seen above that JSON and JavaScript correspond quite well to each other, and one can be projected to another and vice versa. Armed with this fact, server side frameworks generate proxy JavaScript objects on the fly that correspond with the backend data structures. They also inject code that call backend methods asynchronously and pass proxies to and from the client browser.
There are many popular sever side AJAX frameworks such as Microsoft ASP.NET AJAX, AjaxPro, ComfortASP.NET, and MagicAjax.NET. In addition, Microsoft has started a community effort to build more server side controls to bring web experience closer to desktop experience via a community project called ASP.NET AJAX Control Toolkit (although, the last time I checked, there were quite a few bugs in this toolkit and some controls such as AutoComplete were completely broken). I must also mention that the Microsoft ASP.NET AJAX server framework also contains a client side JavaScript library called the Microsoft AJAX library (talk about confusing names) that closely mimics much of the OO features present in managed languages such as inheritance, interfaces etc. The Microsoft AJAX library can be downloaded from http://www.asp.net/ajax/downloads/.
However, one must realize the serious implications of using various server side frameworks in code. Most of the time, these limitations are not very well documented. One common limitation is the use of conflicting HTTP handlers and HTTP modules in ASP.NET projects. HTTP modules and handlers are HTTP request handlers that get executed way before ASP.NET gets to the requests in the application pipeline. Server side frameworks usually utilize these components to inject code into an HTML response via JavaScript tags. However, if there are more than one server frameworks used (maybe for different purposes than AJAX), then they might conflict and suppress functionality offered by other frameworks by ‘stealing’ the HTTP requests first.
Another major limitation of server side frameworks is the way they perform asynchronous HTTP requests. The ASP.NET AJAX framework, for example, relies heavily on the ASP.NET ViewState object. Hence it is impossible to issue requests from web user controls (commonly known as partial views or *.ascx) using this framework. It is also not compatible with the ASP.NET MVC framework. Hence it is important to perform background study of a framework and ensure that it is compatible with existing frameworks being used in your web applications.
Let us see an example of using a server side framework. For the purposes of this example, I will be using the AjaxPro framework. You can download the AjaxPro framework for free from its website. To use this framework, create an ASP.NET web application and simply reference the downloaded assembly (AjaxPro.dll or AjaxPro2.dll depending on the version you download from the website) from your project.
Next, add the following lines in web.config (note: if you already have an httpHandlers
section, just add the ‘add
’ tag from below):
<httpHandlers>
<add verb="POST,GET" path="ajaxpro/*.ashx"
type="AjaxPro.AjaxHandlerFactory,AjaxPro.2"/>
</httpHandlers>
The code above implies that whatever request POST/GET is received for a resource with an extension ashx within the ajaxpro folder must be forwarded to the AjaxPro.AjaxHandlerFactory
HTTP handler defined in the AjaxPro.2.dll assembly.
Next, we will add a new ASP.NET page named AjaxPro_Page to the project. The first thing we need to do in order to hook up this page to the AjaxPro HTTP handler is to register it with AjaxPro. We do this via a AjaxPro.Utility.RegisterTypeForAjax
call from within the page’s Page_Load
method, as follows:
protected void Page_Load(object sender, EventArgs e)
{
AjaxPro.Utility.RegisterTypeForAjax(typeof(AjaxPro_Page));
}
The next step is to define the method(s) on this page that will be called from within this page by the client code. For the purpose of this example, we shall define a GetTime
method that will return the server time to the client. It is important to mark this method with an AjaxMethod
attribute so a “proxy” code for this method can be generated by the AjaxPro framework. Following is the definition of the GetTime
method:
[AjaxMethod]
public DateTime GetTime()
{
return DateTime.Now;
}
At this time, the server part of the code is complete. The complete class should look like:
using System;
using AjaxPro;
public partial class AjaxPro_Page : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
AjaxPro.Utility.RegisterTypeForAjax(typeof(AjaxPro_Page));
}
[AjaxMethod]
public DateTime GetTime()
{
return DateTime.Now;
}
}
Let us run this page in a browser and see what gets generated on the client side. Run this page in a browser and view the source for this page. You will find the following three script
tags that were injected by the AjaxPro.AjaxHandlerFactory
HTTP handler that we registered in the web.config before:
<script type="text/javascript" src="/blogtest/ajaxpro/prototype.ashx"></script>
<script type="text/javascript" src="/blogtest/ajaxpro/core.ashx"></script>
<script type="text/javascript" src="/blogtest/ajaxpro/converter.ashx"></script>
<script type="text/javascript" src="/blogtest/ajaxpro/AjaxPro_Page,App_Web_hghu6cj1.ashx">
</script>
The first script is basically the code that enables OO concepts such as inheritance and virtual functions used within the code generated by AjaxPro in later stages. Hence, it defines the base prototype from which all the AjaxPro client code inherits from. The second script generates code related to the IFrame
, request queues, and general request / response logic. The third script is basically the JSON serializer / deserializer for complex .NET types such as System.Collections.Specialized.NameValueCollection
, System.Data.DataSet
, System.Data.DataTableDataTable
, ProfileBaseConverter
, and IDictionaryConverter
. This enables you to use these complex data types as return types for your .NET methods and use them seamlessly from AjaxPro generated proxy code.
The last script corresponds to the proxy generated for your code-behind. Note that the exact ending of the App_Web_*.ashx handler is random, and may not end with hghu6cj1 as in my case. If you navigate to that URL and view the source for the code, you will find something similar to the code below:
AjaxPro_Page_class = function() {};
Object.extend(AjaxPro_Page_class.prototype, Object.extend(new
AjaxPro.AjaxClass(), {
GetTime: function() {
return
this.invoke("GetTime", {}, this.GetTime.getArguments().slice(0));
},
url: '/blogtest/ajaxpro/AjaxPro_Page,App_Web_hghu6cj1.ashx'
}));
AjaxPro_Page = new AjaxPro_Page_class();
Here, we can clearly see that AjaxPro generates a JavaScript class named AjaxPro_Page_class
and defines the invoke code for the GetTime
method. What it does exactly is define a class AjaxPro_Page_class
as an empty class and then add the GetTime
method to its prototype. This way, any instance of this class or its subclass will have access to the GetTime
method via prototype chaining. Finally, it declares an instance of AjaxPro_Page_class
named AjaxPro_Page
(same name as our server code-behind class) so it can be used from our scripts to invoke methods on the code-behind.
Now, we need to hook up the client code to call this GetTime
method from AjaxPro_Page
. Well, it's simple. Just replace the code in your AjaxPro_Page.aspx with the following:
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="AjaxPro_Page.aspx.cs" Inherits="AjaxPro_Page" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>AjaxPro Example</title>
</head>
<script src="Scripts/jquery-1.3.2.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#cmdServerTime").click(function() {
AjaxPro_Page.GetTime(function(result) {
$("#lblServerTime").text(result.value.toString());
});
});
});
</script>
<body>
<form id="form1" runat="server">
<div>
Server Time: <span id="lblServerTime"></span>
<input type="button" id="cmdServerTime" value="GetServerTime" />
</div>
</form>
</body>
</html>
This code basically declares a span
with id
lblServerTime
and a Button
with id
cmdServerTime
. In the page load jQuery, it hooks up the Click
event of cmdServerTime
to call the AjaxPro_Page.GetTime
method, which in turn is hooked up to the anonymous method that replaces the text for the span
with the server returned time value from the GetTime
method. Run it and you shall see the results similar to the screenshot below:
Figure 5 – AjaxPro example in action
Handling Conflicting HTTP Handlers
As I mentioned before, sometimes multiple HTTP handlers on the server may conflict and your application may not work as desired. Hence, proper resolution may be required to enable all the handlers perform in harmony. As an example, if you try to use the AjaxPro framework with the ASP.NET MVC application, your application will not work out of the box since the MVC framework has a powerful URL routing engine that captures all the incoming requests (note that in the MVC framework, views are also non-existing resources) including all the resource requests for the non-existing resources the ajaxpro/ non existing folder (refer to web.config above). Hence, we need an exclusion for this rule in the ASP.NET MVC URL routing engine. The following code in the Global.asax.cs will achieve this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("ajaxpro/{resource}.ashx");
:
}
Debugging Support
As with any application development, debugging support is a must to trace execution points within the code. I test and debug my web applications in Internet Explorer as well as in Mozilla Firefox. To enable debugging support in IE, you can follow the instructions in Jonathan Boutelle’s blog. A good thing about IE debugging (I personally use Firefox for all other purposes) is that one can leverage the Visual Studio debugger rather than downloading and learning another debugger to debug JavaScript. For Mozilla Firefox, I use the Venkman JavaScript Debugger and strongly recommend it as well.
Conclusion
I hope that I was able to provide a good insight into AJAX web development from a beginner’s point of view. There are many tools available which are not covered here, but the most important thing is to play around with them and find the best combination that works for your needs. I also have my own blog at http://akaila.serveblog.net where I post all of such articles and more. And, of course, if you learn some, share some! Happy coding!