Sei sulla pagina 1di 16

An Introduction to AJAX Techniques and

Frameworks for ASP.NET


Contents

• Introduction
• The Example Web Page
• The Classical ASP.NET Implementation
• Using ASP.NET Callbacks for AJAX
• AJAX meets Atlas
o Using Web Services from JavaScript
o Invoking Page Methods
o Using the UpdatePanel Server Control
• Other ASP.NET AJAX Frameworks
o Ajax.Net
o Anthem.Net
o MagicAjax.Net
• Summary

Introduction

By now, the chances are high that you have heard of AJAX in the context of web
development. The acronym was coined by Jesse James Garret in his article: AJAX: A
New Approach to Web Applications. Several frameworks have emerged since then to
support AJAX Web development. In this article, we will examine some of the
frameworks that are available for ASP.NET programmers. The emphasis of the article
will be on Microsoft's ASP.NET Atlas which is becoming the most important
framework for AJAX development in ASP.NET. We will examine different frameworks
and the benefits of AJAX through an example of a web page in an e-commerce web
site. Let's start by looking at the details of the example.

The Example Web Page

We will develop a simple web page that presents the user with a list of items, sold by
the e-commerce web site, displayed in a list box. When the user selects an item from
the list box, the text below the list box shows the quantity of the selected item in
stock at the warehouse. To properly illustrate the benefits of AJAX, the list-box will
appear below paragraphs of “Lorem Ipsum” text. Here is a screenshot of the
example web page:
The example uses a SQL Server Express database. You can download SQL Server
Express freely from the SQL Server web site. The list of items is maintained in a
table called Items. The table has three columns: ItemID, ItemName, and
ItemQuantity. The list-box is populated by binding it to a SqlDataSource configured
with the Items table. The ItemID field of the table is bound to a list item value, and
the ItemName field is bound to the display text. The markup of the page is shown
below:

Collapse
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>The Classical ASP.NET Way</title>
</head>
<body>
<div class="testContent">
.
Paragraphs of Lorem Ipsum .
</div>
<form id="form1" runat="server">
<div>
<label for="ItemList" accesskey="I">
Items:</label>
<asp:ListBox runat="server" ID="ItemList"
DataSourceID="ItemsSource" DataTextField="ItemName"
DataValueField="ItemID" EnableViewState="False">
</asp:ListBox>
<div id="ItemQuantityDisplay" runat="server">
The item quantity will be displayed here </div>
<asp:SqlDataSource ID="ItemsSource" runat="server"
ConnectionString="<%$ ConnectionStrings:Items %>"
SelectCommand="SELECT [ItemName], [ItemID] FROM [Items]">
</asp:SqlDataSource>
</div>
</form>
</body>
</html>

Let's start by looking at how the web page will be coded in classical ASP.NET.

The Classical ASP.NET Implementation

Our objective is to display the quantity of item in stock when the user selects an item
in the listbox. We can do this by changing the text of the ItemQuantityDisplay div
element. The ItemQuantityDisplay has the attribute runat="server" which allows
server code to modify the text and other attributes of the div element. We set the
listbox’s AutoPostback attribute to true so that the form is automatically posted
back to the server when the listbox selection changes.

protected void Page_Load(object sender, EventArgs e) {


this.MaintainScrollPositionOnPostBack = true;
ItemQuantityDisplay.Visible = false;
}

protected void ItemList_SelectedIndexChanged(object sender, EventArgs e)


{
ItemQuantityDisplay.Visible = true;
try {
ItemQuantityDisplay.InnerText =
String.Format(" {0} in stock",
Warehouse.GetItemQuantity(ItemList.SelectedValue));
} catch (Exception ex) {
Trace.Write("GetItemQuantity Error: " + ex.Message);
ItemQuantityDisplay.InnerText = "Error retrieving quantity";
ItemQuantityDisplay.Attributes["class"] = "Error";
}
}

We have paragraphs of text above the listbox so it is likely that the user may have to
scroll to reach the listbox and change its selection. We set the
MaintainScrollPositionOnPostBack to true so that after the postback completes,
the scroll position of the page is at the same location where the user left it;
otherwise, the user will have to scroll to get to the text displaying the item quantity.

In the ItemList_SelectedIndexChanged, we obtain the quantity of items in the


warehouse by calling the Warehouse.GetItemQuantity method which runs a SQL
query to get the item quantity. We change the text of the ItemQuantityDisplay by
modifying the InnerText property, which is set to display the quantity of items in
stock when no error occurs. If an error occurs, we modify the CSS class of the
ItemQuantityDisplay to “Error” (which is defined in a separate style sheet file) and
set the text to the user to show that an error occurred.
Now, let’s see what the user experiences when he browses to the web page.
Depending on the browser window height, the user may or may not need to scroll to
reach the listbox. Once he reaches the listbox and selects an item, he will see a brief
flicker in the web page and see the quantity of item in stock in the text below the list
box. He will see that the web page scrolls down when the page is reloaded after he
selects the item. Such interaction can no where be termed continuous though
MaintainScrollPositionOnPostback tries to make the discontinuous action of the
postback seem continuous. Now, let’s look at the AJAX version of the same
application.

Continuous Interaction with AJAX

The main promise of AJAX is to provide continuous interaction to users when they
use a web site. Let’s see how we can achieve that. In the AJAX version of our
application, we will obtain the quantity of the selected item in stock by using the
XMLHttpRequest object and use client scripting to alter the text of the
ItemQuantityDisplay. Since the page is not reloaded in its entirety as it was in the
classical web application, we can expect a smoother interaction.

For JavaScript to obtain the quantity of items in stock, we need to provide an end
point in our web site where this information can be obtained. We need to have a URL
from where the item quantity can be obtained. The most straightforward way to do
this is to access the ASP.NET web service methods through the HTTP GET protocol.
The URL is of the form:

http://hostname/path/<webservice>/<methodname>?<name1>=<value1>&<name2>=<value2>

You may have to enable the HTTP GET access to ASP.NET web services in the
web.config file. This can be done by adding a configuration entry to the web.config,
as shown in the following listing:

<configuration>
<system.web>
<webServices>
<protocols>
<add name="HttpGet"/>

Next, we create a web service that provides a method to obtain the quantity of an
item in stock at the warehouse. The code is shown in the following listing:

public class WarehouseService : System.Web.Services.WebService {

[WebMethod]
public int GetItemQuantity(string itemID)
{
return Warehouse.GetItemQuantity(itemID);
}
}

Assuming that the web service is on your local machine and the item ID whose
quantity you want to access is 79ec4891-a73d-4fcc-ade9-2c2a47f7b2df, you can use
the following URL:
http:://localhost/WareHouseService.asmx/GetItemQuantity?
itemID=79ec4891-a73d-4fcc-ade9-2c2a47f7b2df

This will return a response of the following form:

<int xmlns=”…”>85</int>

Now we are ready to code the rest of the application. Since, an AJAX enabled web
page talks to the server asynchronously using JavaScript, it is essential to provide
the user some feedback. Many AJAX web sites show animated GIFs with a text
message. Some of the images that are in the public domain can be downloaded from
here. We select an appropriate image, and modify the ItemQuantityDisplay as
shown in the listing:

<div>
<span id="ItemQuantityDisplay"></span>
<span id="ProgressDisplay" style="display: none">
<img src="images/loading.gif" alt="Loading" />
Checking Stock...
</span>
</div>

We now have a div which encloses two spans with IDs of ItemQuantityDisplay and
ProgressDisplay. The ProgressDisplay display span contains an animated GIF
image, with the text “Checking Stock” on its right side. The ProgressDisplay is
initially hidden. Displaying a feedback while an asynchronous operation is in progress
is merely a matter of hiding the ItemQuantityDisplay span and showing the
ProgressDisplay span; when the asynchronous operation completes, the
ProgressDisplay span is hidden and the ItemQuantityDisplay span is shown.

Next, we need to add JavaScript code that will handle the selection change events
for the ItemList and call asynchronously to the server. This can be either embedded
within the page or in a separate file. A separate file approach is the preferred way in
AJAX applications as script code base tends to be big. The script code in a separate
file means that the code can be cached by the browser independently of the page,
saving some bandwidth. In our example, we put the code in a separate file.

The XMLHttpRequest object is available as a built-in object for Internet Explorer 7.0,
Mozilla Firefox, Opera, and Safari. In Internet Explorer 6.0, it is available as an
ActiveX Object. The JavaScript code shown in the listing below accounts for this
difference:

if (!window.XMLHttpRequest){
window.XMLHttpRequest = function(){
return new ActiveXObject("Microsoft.XMLHTTP");
}
}

This code first checks the availability of the XMLHttpRequest object. If it is not
available, then it adds a new property to the window object of type function. The
function instantiates a new ActiveX object with prog ID Microsoft.XMLHTTP and
returns the object. For simplicity, we ignore those browsers which may not have a
built-in XMLHttpRequest object and which do not support ActiveX objects. This code
allows us to instantiate the XMLHttpRequest object on all browsers:

var xr = new XMLHttpRequest();

This works because properties and methods of the window object are considered
global.

Now, we need to handle the change event for the ItemList. Mozilla Firefox and
other W3C DOM Level 2 compatible browsers provide a method called
addEventListener, where as Internet Explorer provides a method called
attachEvent. Thus our code to add an event handler for the change event will look
like:

if (itemList.attachEvent) {
itemList.attachEvent("onchange", itemList_OnChange);
}
else {
itemList.addEventListener("change", itemList_OnChange, false);
}

The code checks for the existence of the attachEvent method, and if it exists, it
calls the attachEvent method, otherwise it calls addEventListener. Also note the
difference in the event name; in Internet Explorer, it is onchange, and in Mozilla
FireFox, it is change. Welcome to the world of browser incompatibilities!

The main work in our application will be done in the itemList_OnChange function,
shown below:

Collapse
function itemList_OnChange(){
var xr = new XMLHttpRequest();
xr.open("GET",
"WarehouseService.asmx/GetItemQuantity?itemID=" + itemList.value, true);
xr.onreadystatechange = function() {
if (xr.readyState == 4) {
if (xr.status == 200) { //Successful Request
var doc = xr.responseXML;
var qty;

if (doc.evaluate) {
qty = doc.evaluate("//text()", doc,
//XML Parsing in Mozilla
null,
XPathResult.STRING_TYPE, null).stringValue;
}
else {
//XML Parsing in IE
qty = doc.selectSingleNode("//text()").data;
}

itemQuantityDisplay.innerHTML = qty + " in stock";


itemQuantityDisplay.className = "";
} else {
itemQuantityDisplay.innerHTML = "Error retrieving quantity";
itemQuantityDisplay.className = "Error";
}
//Hide Progress
itemQuantityDisplay.style.display = "";
progressDisplay.style.display = "none";
}
}
xr.send(null);

//Display progress
progressDisplay.style.display = "";
itemQuantityDisplay.style.display = "none";
}

We can see the four steps involved in using the XMLHttpRequest object:

1. Instantiate the XMLHttpRequest object.


2. Call the open method on the XMLHttpRequest object. The first parameter is
the HTTP method to use, which is either GET or POST. The second parameter
is the URL of the resource that you want to access using the object.
3. Provide a handler to the onreadystatechange event. The handler will be
called by the object as its state changes. The bulk of the work is done in this
handler. In the listing, we assign an anonymous function to handle this event.
4. Call the send method. The send method can take the contents of the request
as a string. This is useful for posting to the server using HTTP POST.

When the HTTP request ends, either successfully or with errors, the readyState of
the XMLHttpRequest object is set to 4, which means complete. You have to figure
whether the request was successful or not using the status property which returns
one of the HTTP status codes. The status code of 200 means success. Once the
request completes, the HTTP response can be obtained from either the responseXML
property, which returns the response as an XML DOM document (provided the
content of the response is XML), or the responseText property, which returns the
response in plain text.

In our case, the response is an XML document, and we need to extract the item
quantity from the XML DOM document. Since the quantity of the item is send as text
of the root document, the XPATH //text() will work for us. The exact method of
using XPath is different for Internet Explorer and Mozilla Firefox. In Internet
Explorer, you can use the selectSingleNode function, which is not available in
Mozilla where you have to use the evaluate method. Luckily, this is the last piece of
code where we have to consider cross-browser compatibility issues.

The other interesting thing we do in the code for the event handler is hiding and
displaying the progress by manipulating the display property of the element’s
style. When the HTTP request is sent, we hide the ItemQuantityDisplay and show
the ProgressDisplay, and when the request is finished, we do the reverse.

Let’s examine the application from the user interaction perspective, and compare it
with the classic ASP.NET application in the previous section. When the user scrolls
down to the item list and selects an item, he sees an animation with the text
“Checking Stock...” on its right side. The animation disappears after some time, and
the user sees either the quantity of items or an error message. There is no screen
flicker, and the scroll position does not change. This can be described as a
continuous interaction.

This continuous interaction did come at a price. The price being the amount of client-
side code we had to write. Fortunately, the client-side code can be simplified. The
simplification can be done by encapsulating common code in a framework. Luckily,
ASP.NET callbacks provide an elementary framework for calling server-side code
from client scripts. We examine that in the next section.

Using ASP.NET Callbacks for AJAX

ASP.NET 2.0 has a feature called callbacks which allow controls to call server-side
code on a page without a full postback. The callback mechanism is used by the
TreeView control, the GridView control, and the DetailsView control. The TreeView
control uses callbacks to expand nodes on demand; the GridView uses callbacks for
sorting and paging; the DetailsView control uses callbacks for paging.

The steps involved in using callbacks are the following:

1. Implement the ICallbackEventHandler interface in the control or the Page


class. The interface has two methods: RaiseCallbackEvent and
GetCallbackResult. RaiseCallbackEvent takes a string argument which is
supplied from the client script invoking the callback; the GetCallbackResult
returns a string value which is passed to the client script.
2. Generate the client-side script that will invoke the callback. This can be
generated by calling the GetCallbackEventReference method of
ClientScriptManager. An instance of ClientScriptManager is available
from the Page class’s ClientScript property.
3. Write code that invokes the client script code generated in step 2. This will
probably be done in an event handler.

The following listing shows the implementation of ICallbackEventHandler:

public string GetCallbackResult()


{
return callbackResult;
}

public void RaiseCallbackEvent(string eventArgument)


{
try {
callbackResult = Warehouse.GetItemQuantity(eventArgument).ToString();
}
catch (Exception e)
{
Trace.Write(e.Message);
throw new Exception("Error checking quantity");
}
}

The eventArgument parameter of the RaiseCallbackEvent function is passed from


the client script. In our example, this will be the ItemID of the selected item in the
ItemList listbox. All the RaiseCallbackEvent method implementation needs to do
is to obtain the item quantity from the eventArgument parameter and put it in a
string member variable of the Page. We need a member variable to store the result
as we will need to return this in the GetCallbackResult method.

Implementation of ICallbackEventHandler is just a part of the story. Next, we need


to generate the client-side script which actually invokes the script. This is done in the
Load event handler of the Page, as shown below:

protected void Page_Load(object sender, EventArgs e) {


if (IsCallback)
return;

string callBackFunctionCall =
ClientScript.GetCallbackEventReference(
this,
"getSelectedItemID()",
"onCallbackComplete",
null,
"onCallbackError",
true
);

Page.ClientScript.RegisterClientScriptBlock(
GetType(),
"CallBack",
"function DoClientCallBack() { "
+ callBackFunctionCall + "} ",
true
);
}

Generating client-side code is a two step process. First, we call the


GetCallbackEventReference method. This method takes six parameters:

1. The first parameter is an instance of the class which implements


ICallbackEventHandler. In our example, this will be the Page itself.
2. The second parameter is the value that needs to be passed to the
RaiseCallbackEvent method. The parameter should be a JavaScript
expression that evaluates to a string. In our example, we need to pass the
selected item value in the listbox. To do this, we create a function
getSelectedItemID which returns the selected item value in the listbox. We
pass the string getSelectedItemID(), which evaluates to the return value
from the function, in this parameter.
3. The third parameter is the client script function to be called when the callback
completes. This function is passed the string value returned from the
GetCallbackResult.
4. The fourth parameter is a context that can be associated with the callback
instance. If there are many callbacks, this parameter can be used to
distinguish between them. This parameter has to be a JavaScript expression.
5. The fifth parameter is the name of the JavaScript function which gets called
when an error occurs during the callback process.
6. The final parameter is a boolean value that indicates whether the callback
should be synchronous or asynchronous. Since we want to perform an
asynchronous operation, we pass true as the value of this parameter.
The return value from GetCallbackEventReference is a JavaScript expression that
makes an asynchronous call to the server. We will put this in a separate JavaScript
function called DoClientCallBack, which will in turn be called by the change event
handler of the ItemList element. We use the
ClientScript.RegisterClientScriptBlock function to form the JavaScript function
and register the inline script block. This completes the work we have to do on the
server. Next, we move to the code on the client.

As usual, we need to attach an event handler to handle the change event of the
ItemList control. The code is as shown:

//Callback success
function onCallbackComplete(result, context){
progressDisplay.style.display = "none";

itemQuantityDisplay.className = "";
itemQuantityDisplay.style.display = "";
itemQuantityDisplay.innerHTML = result + " in stock";
}

//Callback error
function onCallbackError(){
progressDisplay.style.display = "none";

itemQuantityDisplay.className = "Error";
itemQuantityDisplay.style.display = "";
itemQuantityDisplay.innerHTML = "Error retrieving quantity";
}

function itemList_OnChange()
{
document.getElementById("ProgressDisplay").style.display = "";
document.getElementById("ItemQuantityDisplay").style.display = "none";
DoClientCallBack();
}

The user interaction in this example is the same as that presented in the previous
section, but we can see that the client code is greatly simplified as we no longer have
any code to parse the XML or to work with the XMLHttpRequest object. The ASP.NET
callback mechanism takes care of the low level calls; however, we did have to add
extra code on the server.

AJAX meets Atlas

Atlas was built to ease development of AJAX applications. The other great advantage
of Atlas is that it makes your code compatible across browsers. You don’t have to
worry about the differences between the browsers; it is taken care by Atlas most of
the time. We will see how this is done in the next section.

Using Web Services from JavaScript

There are a number ways to implement our example in Atlas. A core feature of Atlas
is the ability to invoke web services from JavaScript code. First, we will use this
feature of Atlas. Since we already have a web service in place which we developed
for an example in one of the preceding sections, our task is greatly simplified.
The first step to use Atlas is to add Atlas script references to the web page. This is
done by adding a ScriptManager control to the web page where you intend to use
Atlas. The ScriptManager control takes care of generating appropriate script
references for Atlas framework scripts. It can also generate script references for web
service proxies (which are automatically generated by Atlas) and also your own
custom scripts which may depend on Atlas. The following listing demonstrates the
use of the Atlas ScriptManager control.

<atlas:ScriptManager EnableScriptComponents="false" ID="ScriptManager1"


runat="server">
<Services>
<atlas:ServiceReference
GenerateProxy="true"
Path="WarehouseService.asmx" />
</Services>
<Scripts>
<atlas:ScriptReference
Path="ScriptLibrary/AtlasExample.js" />
</Scripts>
</atlas:ScriptManager>

The code shown in the listing is all the code you need to add to the web page. The
rest of the code, which is in a JavaScript file, is shown below:

Collapse
var itemList, itemQuantityDisplay, progressDisplay;

function onCallbackComplete(result){
progressDisplay.style.display = "none";

itemQuantityDisplay.className = "";
itemQuantityDisplay.style.display = "";
itemQuantityDisplay.innerHTML = result + " in stock";
}

function onCallbackError(){
progressDisplay.style.display = "none";

itemQuantityDisplay.className = "Error";
itemQuantityDisplay.style.display = "";
itemQuantityDisplay.innerHTML = "Error retrieving quantity";
}

function itemList_OnChange(){
progressDisplay.style.display = "";
itemQuantityDisplay.style.display = "none";

//Invoking the web service


WarehouseService.GetItemQuantity(itemList.value,
onCallbackComplete,
onCallbackError,
onCallbackError);
}

Sys.Runtime.load.add(function() {
itemList = document.getElementById("ItemList");
itemQuantityDisplay = document.getElementById("ItemQuantityDisplay");
progressDisplay = document.getElementById("ProgressDisplay");

//Attaching the event handler


itemList.attachEvent("onchange", itemList_OnChange);
});

The major thing to notice here is the ease of invoking the web service. The web
service method is invoked as a regular function call in JavaScript. The results are
obtained with the same ease. The Atlas framework takes care of the construction of
the URL, sending calls to the web service, and parsing the return values. The details
of the XMLHttpRequest object are completely shielded.

The other thing to notice in the above listing is the use of the attachEvent function
to add an event handler. There is no special consideration for different browsers. The
code just works with Mozilla Firefox and Internet Explorer. This is all made possible
by the Atlas cross browser compatibility layer.

Invoking Page Methods from JavaScript

Another way Atlas enables JavaScript code to call server code is through Page
methods. You can apply the WebMethod attribute to a method in your Page class, and
this method will automatically be available to the JavaScript code. Let's convert our
example to use Page methods.

First, we will need to mark a method with the WebMethod attribute:

[System.Web.Services.WebMethod]
public int GetItemQuantity() {
return Warehouse.GetItemQuantity(ItemList.SelectedValue);
}

Notice the use of ItemList.SelectedValue. In a Page method, all the control values
can be accessed as they can be accessed in a postback. So use page methods
whenever you require values of other server controls in the method. The JavaScript
code will remain almost the same as in the previous section except for the actual
web method invocation. This was how the call was made in the previous section:

//Invoking the web service


WarehouseService.GetItemQuantity(itemList.value,
onCallbackComplete,
onCallbackError,
onCallbackError);

This is how you will make a call to a page method:

PageMethods.GetItemQuantity(onCallbackComplete,
onCallbackError,
onCallbackError);

All the different ways we have considered so far, except for the postback sample,
required us to use JavaScript. Atlas provides a server control called UpdatePanel
which allows you to develop AJAX applications with little or no JavaScript. Let's see
how we can use an UpdatePanel for our example.

Using the UpdatePanel Server Control


To use an UpdatePanel, you need to place the content which needs to be updated
after an AJAX call inside the UpdatePanel. As we want the ItemQuantityDisplay
div to be updated, we place it inside the UpdatePanel:

<atlas:UpdatePanel ID="ItemQunatityDisplayPanel" Mode="conditional"


runat="server">
<ContentTemplate>
<div id="ItemQuantityDisplay" runat="server">
</div>
</ContentTemplate>
<Triggers>
<atlas:ControlEventTrigger
ControlID="ItemList"
EventName="SelectedIndexChanged" />
</Triggers>
</atlas:UpdatePanel>

As we can see, the UpdatePanel declaration has two parts:

1. The ContentTemplate contains the ASP.NET markup for server controls and
the HTML which needs to be dynamically updated.
2. The Triggers section describes what events actually should cause the
UpdatePanel contents to be rendered. In the listing above, we indicate that if
the SelectedIndexChanged event is fired on the ItemList control, then the
UpdatePanel contents should be updated.

You also need to set the property EnablePartialRendering of the ScriptManager


control to true:

<atlas:ScriptManager ID="ScriptManager1" runat="server"


EnablePartialRendering="true">

Setting EnablePartialRendering to true enables the ScriptManager to control the


rendering of the page as described later. The server side C# code is listed below:

protected void Page_Load(object sender, EventArgs e) {


if (!IsPostback)
ItemQuantityDisplay.Visible = false;
}

protected void ItemList_SelectedIndexChanged(object sender, EventArgs e) {


ItemQuantityDisplay.Visible = true;

try {
ItemQuantityDisplay.InnerText =
String.Format(" {0} in stock",
Warehouse.GetItemQuantity(ItemList.SelectedValue));
} catch (Exception ex) {
Trace.Write("GetItemQuantity Error: " + ex.Message);
ItemQuantityDisplay.InnerText = "Error retrieving quantity";
ItemQuantityDisplay.Attributes["class"] = "Error";
}
}

As you might have noticed, the code looks like typical ASP.NET server code in
response to a form postback. Yet, when you run the application, you will see that its
behavior is similar to the other AJAX examples and you have not written a single line
of JavaScript. So how does it all work?

What happens is that any kind of client events which cause a postback are
intercepted by the Atlas client framework. The form contents are then posted using
the XMLHttpRequest object through JavaScript. From the server perspective, it is like
a normal postback, but from the client perspective, the form is not submitted as the
browser retains the web page state intact. The server side code then scans through
all the UpdatePanels on the page, and checks if they need to be rendered or
updated on the client side. This is done by checking the trigger. Only the portions of
the page that are inside an UpdatePanel, which is triggered for an update, are
actually rendered, and instead of sending the page's response as HTML, it is send as
XML. The client-side script then parses the response XML and extracts and replaces
the updated UpdatePanels's contents.

To display progress message to the user when an UpdatePanel is being updated, a


server control called UpdateProgress is made available. The contents of the
UpdateProgress server control are automatically displayed when the client sends
update requests to the web server, and hidden once the update is done.

<atlas:UpdateProgress ID="ProgressDisplay" runat="server">


<ProgressTemplate>
<img src="images/loading.gif" alt="Loading" />
Checking Stock...
</ProgressTemplate>
</atlas:UpdateProgress>

Of course, there is lot more to the UpdatePanel control, and it will require a separate
article in itself. The UpdatePanel control is the most important feature of Atlas, and
it will be the primary way Atlas will be used. We have seen here some of the features
of Atlas, now, let's examine a few other frameworks.

Other AJAX Frameworks for ASP.NET

Before ASP.NET Atlas was developed, there were several open source
implementations to provide AJAX support in ASP.NET. Let's quickly scan through
three of the popular open source implementations.

Ajax.NET

Ajax.NET, developed by Michael Schwartz, prides itself to be the first AJAX library for
ASP.NET. To use Ajax.NET, you need to download the AjaxPro assembly from the
AjaxPro.info web site and place it in the bin directory of your web site. The server
code resembles that of Atlas when using page methods, only the name of the
attribute changes:

void Page_Load(object sender, EventArgs e) {


AjaxPro.Utility.RegisterTypeForAjax(GetType());
}

[AjaxPro.AjaxMethod]
public int GetItemQuantity(string itemID) {
return Warehouse.GetItemQuantity(itemID);
}

Here is how you invoke this method from JavaScript:

Intro.AjaxNetExample.GetItemQuantity(itemList.value, onCallbackComplete,
onCallbackError);

Intro.AjaxNetExample is the name of the class of the ASP.NET page which is


specified in the @Page declaration:

<%@ Page Language="C#" AutoEventWireup="true"


ClassName="Intro.AjaxNetExample" %>

Ajax.Net is a lightweight library, and it does not support Atlas functionalities like
cross-browser compatibility, server side controls etc. However, you can use many of
the free JavaScript libraries for other DHTML work.

Anthem.Net

Anthem.Net was developed by Jason Diamond, and it supports AJAX in ASP.NET


through server controls. It has a set of server controls that extend the regular
ASP.NET server controls. To enable our application using Anthem.net, we have to
replace the regular ASP.NET controls with Anthem.Net's controls.

<div>
<label for="ItemList" accesskey="I">
Items:</label>
<anthem:ListBox runat="server" ID="ItemList" DataSourceID="ItemsSource"
DataTextField="ItemName"
DataValueField="ItemID" EnableViewState="False" AutoCallBack="True"
OnSelectedIndexChanged="ItemList_SelectedIndexChanged">
</anthem:ListBox>
<anthem:Panel AutoUpdateAfterCallBack="true" runat="server">
<div id="ItemQuantityDisplay" runat="server">
</div>
</anthem:Panel>
<asp:SqlDataSource ID="ItemsSource" runat="server"
ConnectionString="<%$ ConnectionStrings:Items %>"
SelectCommand="SELECT [ItemName], [ItemID] FROM [Items]">
</asp:SqlDataSource>
</div>

So we replaced the listbox with Anthem's listbox. Notice that the AutoCallback
property is set to true. This ensures that when the listbox selection changes, the
Anthem framework will use XMLHttpRequest to post the contents of the form. This
callback works in conjunction with the AutoUpdateAfterCallback property of the
anthem:panel control in the page. Anthem framework looks for updated controls,
and sends it back to the client which just replaces the HTML of the updated controls.

Magic Ajax

The final AJAX framework we are going to look at is the MagicAjax framework. This
started as a CodeProject article by Argiris Kirtzidis. In terms of use, MagicAjax is
very much similar to using Atlas UpdatePanel. You need to enclose the controls and
markup that you want to update in the MagicAjax's AjaxPanel class.

<magicAjax:AjaxPanel runat="server" ID="MagicAjaxPanel">


<asp:ListBox runat="server" ID="ItemList" DataSourceID="ItemsSource"
DataTextField="ItemName"
DataValueField="ItemID" EnableViewState="False" AutoPostBack="True"
OnSelectedIndexChanged="ItemList_SelectedIndexChanged">
</asp:ListBox>

<div id="ItemQuantityDisplay" runat="server">


</div>
</magicAjax:AjaxPanel>

The server-side code is almost the same as the postback version of the sample in
one of the preceding sections. MagicAjax does not require any kind of JavaScript.

Summary

So we have seen different implementations of a sample in different ways using


different frameworks. Exactly what framework you need to use depends on the
project and the features you desire from a framework. Atlas is being developed by
Microsoft, and is the most feature intensive of all the frameworks; however, Atlas is
quite heavyweight compared to the other three frameworks. MagicAjax.NET and
Anthem.NET are well suited for lightweight and quick AJAX implementations with full
server control support. Ajax.NET is good for lightweight remote calls using
JavaScript. ASP.NET callbacks are well suited for control authors who want AJAX
functionality for a server control.

The source code includes all the implementations which we have discussed. As usual,
comments are welcome.