Background
Asynchronous JavaScript and XML or AJAX has been the revolutionary technology that enabled rich user experience over the web, much like 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 dynamically update a web page via background asynchronous posts to the server. Hence it removes the necessity of sending entire page back to the server and cause global refresh in the browser. This results in following major benefits:
- Rich user experience – a web user doesn’t have to wait until the entire page is loaded. Nor is he / she is 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, hence 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 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 AJAX web application model are as follows:
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 XMLHttpRequest JavaScript class, refer to 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 blog I promised you 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 content with the following:
<?xml version="1.0" encoding="iso-8859-1"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
Next create a 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; // Indicates completion state of XMLHttpRequest object
// Provide the XMLHttpRequest class for IE 5.x-6.x:
// Other browsers (including IE 7.x-8.x) ignore this
// when XMLHttpRequest is predefined
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() {
// Create XMLHttpRequest object
request = new XMLHttpRequest();
// Open an XML file
request.open('GET', 'note.xml', true);
// Attach completion handler to the request
request.onreadystatechange = DisplayXmlFile;
// Send async request to the server with null context
request.send(null);
}
function DisplayXmlFile() {
// If request is complete, show the content of response in the xmlSpan span
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 content 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, the 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 have 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 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 following categories have their own benefits and drawbacks. The decision to pick one over the other depends in the nature of application being developed and 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 ASP.NET MVC Framework and in the near future will be a part of 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 had to create XMLHttpRequest object and check for browser type while doing so. Also we didn’t had to declare constants to check states for XMLHttpRequest object. Just a precise subscription to 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 POST version of 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 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 now 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 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 WebMethod attribute on 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 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 txtFirstName and txtLastName fields via 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, hence it deserializes the person object from JSON to actual Person instance and also serializes the resulting Person object from GetPerson back to JSON. Also notice the JSON string construction from client script in content string object. We specify the key of the object to be ‘person’ which is the same name as the formal parameter name of Person object in GetPerson web method. This allows for binding of parameters during the call so value 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 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 backend data structures. They also inject code that call backend methods asynchronously and pass proxies to and from 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 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 Microsoft ASP.NET AJAX server framework also contain a client side JavaScript library called Microsoft AJAX library (talk about confusing names) that closely mimics much of OO features present in managed languages such as inheritance, interfaces etc. Microsoft AJAX library can be downloaded from http://www.asp.net/ajax/downloads/.
However one must realize 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 HTML response via JavaScript tags. However if there are more than one server frameworks used (maybe for different purposes than AJAX) than 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. ASP.NET AJAX framework for example relies heavily on 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 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 server side framework. For the purpose of this example I will use AjaxPro framework. You can download 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 a 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 extension ashx within the ajaxpro folder must be forwarded to AjaxPro.AjaxHandlerFactory http handler defined in 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 AjaxPro http handler is to register it with AjaxPro. We do this via AjaxPro.Utility.RegisterTypeForAjax call from within 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 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 server time to the client. It is important to mark this method with AjaxMethod attribute so a “proxy” code for this method can be generated by the AjaxPro framework. Following is the definition of 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 as follows:
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 browser and see what gets generated on the client side. Run this page in browser and view the source for this page. You will find following three script tags that were injected by AjaxPro.AjaxHandlerFactory http handler that we registered in 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 core related to IFrame, request queues and general request / response logic. 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 this 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 invoke code for GetTime method. What it does exactly is define a class AjaxPro_Page_class as an empty class and then add 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 its 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 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 GetTime method. Run it and you shall see the results similar to below screenshot:
Figure 5 – AjaxPro example in action
Handling conflicting http handlers
As I mentioned before sometimes multiple http handlers on 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 AjaxPro framework with ASP.NET MVC application your application will not work out of the box since MVC framework has a powerful url routing engine that captures all the incoming requests (note that in 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 both 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. Good thing about IE debugging (I personally use Firefox for all other purposes) is that one can leverage Visual Studio debugger rather than downloading and learning another debugger to debug JavaScript. For Mozilla Firefox, I use 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. And of course if you learn some, share some ! Happy coding !