Integrating Ajax into Web Appliations (Part 2)

Mar 3, 01:45 pm
tags: ,

Introduction

This is the follow-up article to http://www.asptoday.com/content.aspx, and aims to compare three popular Ajax .NET frameworks, Atlas, Anthem.NET and Ajax.NET professional. In the previous article, I introduced a couple of parallel simple samples that work with each of those frameworks, and I'm going to continue developing those here, (so if you haven't read the previous article, you might want to do so now).

After having discussed some more examples that build around a real-time progressbar, I'll discuss shortly a few key points with respect of the capabilities of each framework to ease Ajax development.

Then I'll show you a simple feature-comparing table where you can determine which framework would suit you best with respect to your current development.

System Requirements

To run the sample code provided by the frameworks as well as included in the download material you will need to have the following:

  • A web server running on Windows XP or Windows Server 2003 or later
  • The .NET Framework version 1.x / 2.0
  • VS.NET2003 / 2005 (see note) or Visual Web Developer
  • A web browser - it can be IE6, IE7, FF 1.5 for Windows but also Safari 1.2+ on Mac OSX - all samples should work

Installing and Compiling the Sample Code

All the samples are written using C# with VS 2005 and were generated from a Web Site project. There are implementation specific samples you can obtain by downloading them from their respective websites. For more information, check the Related Links section.

For each of the frameworks discussed in this article and where possible there are specific samples available in the download material. Each sample has an install.txt file which describes what you should do in order to get the sample up and running quickly.

The directory structure of the download for this article is as follows: it contains three directories named AtlasSample, AnthemNETSample, and AjaxNETSample. Each one contains project files that you can open in VS.NET 2005 using Open | Web Site. But before doing so, you'll need to add the corresponding libraries first.

The Sample Applications

In this section I will finish up the discussion around the sample applications.

Example 3: ProgressBar Waiting for the Web Server

This example first shows a simple version of a progressbar (see Figure 1) that notifies the user of work being done on the web server.

Atlas

Figure 1. Example 3 : Progressbar waiting for the web server in Atlas

Here, the callback is initiated by clicking the server button control:

<asp:Button ID="btnFillTable1" 
   OnClientClick="preCBF_btnFillTable1()"...

This has a property OnClientClick to indicate it will run a client-side function called preCBF_btnFillTable1():

var cnt1 = 4000;
function preCBF_btnFillTable1() {
    document.getElementById("divProgressBar1").style.background = "white";
    document.getElementById('txtPerc1').value = "0%";
    document.getElementById('btnFillTable1').value = "Working...";
    document.getElementById('btnFillTable1').disabled = true;
    window.status = "Getting data from web server... ";
    AtlasSample.GetDoSomeWorkService.DoSomeWork(_
        cnt1,postCBF_btnFillTable1);
}

As you can see from the code, the progressbar is simply a <div> control that changes its background color property. For the bordercolor having its width fixed and color visible at all times, the progressbar <div> is wrapped inside another <div>.

The function preCBF_btnFillTable1() calls the server method DoSomeWork() and simulates some work that takes 4 seconds (cnt1) to complete on the server:

[WebMethod]
public void DoSomeWork(int Cnt)
{
    System.Threading.Thread.Sleep(Cnt);
{

In this case the server method only ticks away the amount of milliseconds passed on, and then returns to the JavaScript function postCBF_btnFillTable1():

function postCBF_btnFillTable1() {
    document.getElementById("divProgressBar1").style.background = "yellow";
    document.getElementById('txtPerc1').value = "100%";
    document.getElementById('btnFillTable1').value = "Get data...";
    document.getElementById('btnFillTable1').disabled = false;
    window.status = "Getting data from web server... done.";
}

This actually does a rather silly thing - it fills the progressbar's <div> with the color yellow, but only after the web server has completed. While it works, you need a way to provide a more visible indication to show the web server is really doing its job.

During the callback, the control looks like Figure 2 (nothing seems to be happening):

Figure 2. Example 3:Progressbar while server method is running

After the work on the server is complete, the client notifies the user as shown in Figure 3:

Figure 3. Example 3:Progrssbar showing the work is completed

Anthem.NET

In Anthem.NET, things are a bit different since you can now use one of the special controls from the collection that comes with the library - here you use the <anthem:Button>:

<anthem:Button ID="btnFillTable1" runat="server"
    OnClick="btnFillTable1_Click1" Style="z-index: 100; left: 20px;
    position: absolute; top: 93px" Text="Get data..." Width="126px"
    TextDuringCallBack="Working..."
    AutoUpdateAfterCallBack="false" EnabledDuringCallBack="False"
    PreCallBackFunction="preCBF_btnFillTable1"
    PostCallBackFunction="postCBF_btnFillTable1"
    EnableViewState="False" />

This is a completely new way of using a control and very well integrated into the way controls are programmed in ASP.NET. First note that some new unique properties have been added that make the use of the Anthem controls (here anthem:Button) much richer and ease web development.

For example, the properties PreCallBackFunction and PostCallBackFunction let you execute JavaScript functions before and after the callback process. TextDuringCallback is also a useful property which lets you set a text string, which is displayed during a callback. And AutoUpdateAfterCallBack lets you define if the control should auto update itself after a callback. Finally, EnabledDuringCallBack permits you to disable the control during the callback, which is very useful in applications where a button should be clicked only once per transaction.

Next, the function preCBF_btnFillTable1() is executed:

function preCBF_btnFillTable1() {

document.getElementById("divProgressBar1").style.background = "white";

document.getElementById('txtPerc1').value = "0%";

window.status = "Getting data from web server... ";

}

Since the call into the method is absent here, how is it declared then? Well, the anthem:Button (and as a matter of fact, the other anthem-ized controls also) have a redefined the OnClick() event handler: it doesn't do a postback but a callback. It is a bit of a trick, because in this framework, when the callback starts, the page with its viewstate and control collection that is to be updated is returned to the web server. There it is processed as usual, but when the result is returned, Anthem.NET intercepts it and passes only the necessary data returned to the JavaScript function that is needed to update the page controls.

The web server page method (as defined in the button control declaration) here is named btnFillTable1_Click1() and does the following:

protected void btnFillTable1_Click1(object sender, EventArgs e) {
    this.blnWorking = true;
    while (this.blnWorking)
    {
        System.Threading.Thread.Sleep(100);
        iCounter++;
        if (this.iCounter == 50)
            this.blnWorking = false;
    }
}

What the server is doing here is just simulating work by counting slowly to 50 and then returning. In reality this is where you would do your own processing.

When the callback returns, the anthem:Button property PostCallBackFunction defines the function to execute:

function postCBF_btnFillTable1() {
    document.getElementById("divProgressBar1").style.background = "yellow";
    document.getElementById('txtPerc1').value = "100%";
    window.status = "Getting data from web server... done.";
}

This simply colors the <div> yellow among a couple of other things. Although it is showing how Ajax-like web applications behave, it is not very useful yet, so I decided to add real-time web server progress to it. The result is the next and last to be covered

Ajax.NET Professional

Here, the button is of type HTML:

<input id="btnFillTable1" onclick="preCBF_btnFillTable1()"

The JavaScript function this time has a call into the page method:

var cnt1 = 4000;
function preCBF_btnFillTable1() {
    document.getElementById("divProgressBar1").style.background = "white";
    document.getElementById('txtPerc1').value = "0%";
    document.getElementById("btnFillTable1").value = "Working...";
    document.getElementById("btnFillTable1").disabled = true;
    window.status = "Getting data from web server... ";
    AjaxNETSample._Default.DoSomeWork(cnt1, postCBF_btnFillTable1);
}

The method DoSomeWork() is the same as was used previously and waits 4000 (cnt1) milliseconds. The callback returns and executes the function postCBF_btnFillTable1():

function postCBF_btnFillTable1() {
    document.getElementById("divProgressBar1").style.background = "yellow";
    document.getElementById('txtPerc1').value = "100%";
    document.getElementById("btnFillTable1").value = "Get data...";
    document.getElementById("btnFillTable1").disabled = false;
    window.status = "Getting data from web server... done.";
  }

As you can see, this is the same as with the other implementations.

Example 4: Progressbar Interactively Communicates with the Web Server

This last example will show a more advanced progressbar that will show your users real-time progress on the web server as shown in Figure 4.

Atlas

Figure 4. Example 4: The progressbar before starting the updates

To initiate the callback, click the Get data… button.

<asp:Button ID="btnFillTable3" OnClientClick="populateTable();
    return false;"...

As expected, the JavaScript function populateTable() is executed:

var countStatus3 = 0;
var countRepeat3 = 0;
var ft;
var iMaxNum = 49;
function populateTable() {
    window.status = "Getting data from web server... ";
    document.getElementById('btnFillTable3').value = "Working...";
    document.getElementById('btnFillTable3').disabled = true;
    // clear div if already run once
    if (countStatus3 == -1) {
        ClearProgressBar();
    }
    AtlasSample.GetUpdateCounterService.UpdateCounter(countStatus3, 
      postPopulateTable);
    // continiously execute method....
    ft = window.setTimeout("populateTable()", 250);
    if (countStatus3 ==  iMaxNum )
    {
        window.clearTimeout(ft);
        countStatus3 = -1; // for next click
        document.getElementById('btnFillTable3').value = "Get 
          data...";
        document.getElementById('btnFillTable3').disabled = false;
        window.status = "Getting data from web server... done.";
    }
    document.getElementById('txtcountStatus3').value = countStatus3;
}

The key is in the line:

ft = window.setTimeout("populateTable()", 250);

All this does is repeatedly execute the callback with an interval of 250 msec and returns the web server progress status. It does so until all the work is completed on the server.

The server method that gets called each time is UpdateCounter():

[WebMethod]
public int UpdateCounter(int iCounter)
{
    System.Threading.Thread.Sleep(100);
    iCounter++;
    return iCounter;
}

Here the code simulates work by doing nothing, but of course in practice this would be some serious data processing that would return a real-time percentage, which is then returned to the client browser for processing.

The JavaScript function postPopulateTable() that is run each time the callback returns with data from the server is as follows:

function postPopulateTable(result) {
    document.getElementById("divProgressBar2").style.backgroundColor = 
      "red";
    document.getElementById("divProgressBar2").style.width = result*5 + 
      "px";
    countStatus3 = result;
    document.getElementById('txtPerc3').value = countStatus3*2 + "%";
    if (countStatus3 == 50) {
        countStatus3 = -1;
        countRepeat3++;
    }
}

Filling the <div> works as follows, the <div> that wraps divProgressBar2 has a fixed width of 250 px which means that the inner <div> can have a variable width of 0-250 px. The web server method works with a counter that counts from 0-50 which corresponds to 0-100% shown in the progressbar. This means that the progressbar should be filled 50 times with 5 px to completely fill the progressbar when 100% processing is reached.

Returning 50 from the server is actually a value computed on the server and not on the client. It is therefore an indication of real work done at the server which is reflected by the client progressbar.

When the progressbar needs refreshing the function ClearProgressBar() is executed:

function ClearProgressBar() {
    if (countRepeat3 == 1) {
        alert("Hey, you've already run this once! :-)");
    }
    else {
        alert("Hey, you've already run this " + countRepeat3 + 
          " times! :-)");
    }
    document.getElementById("divProgressBar2").style.background = "white";
    document.getElementById('txtPerc3').value = "0%";
    countStatus3 = 0;
}

The function determines if the process has been run previously and then initializes the controls and a variable before repeating the process.

During the callback the example looks like Figure 5

Figure 5. Example 4: The progressbar being updated in real time

After the process on the web server has completed, the JavaScript execution is halted and the final result looks like Figure 6

Figure 6. Example 4 The progressbar upon completion

Anthem.NET

In Anthem.NET, the callback is started with a normal server button (you could of course use an anthem:Button also):

<asp:Button ID="btnFillTable3" OnClientClick="populateTable();
    return false;"...

The function populateTable() is called:

var countStatus3 = 0;
var countRepeat3 = 0;
var ft;
var iMaxNum = 49;
function populateTable() 
{
    window.status = "Getting data from web server... ";
    document.getElementById('btnFillTable3').value = "Working...";
    document.getElementById('btnFillTable3').disabled = true;
    // clear div if already run once
    if (countStatus3 == -1) {
        ClearProgressBar();
    }
    // callback into server method using Anthem.NET and anonymous function
    Anthem_InvokePageMethod('UpdateCounter',[countStatus3],
      function(result) 
    {
        document.getElementById("divProgressBar2").style.backgroundColor = 
          "red";
        document.getElementById("divProgressBar2").style.width =  
          result.value*5 + "px";
        countStatus3 = result.value;
        document.getElementById('txtPerc3').value = countStatus3*2 + "%";
        if (countStatus3 == 50) {
            countStatus3 = -1;
            countRepeat3++;
        }
    }
    // continiously execute method....
    ft = window.setTimeout("populateTable()", 250);
    if (countStatus3 == iMaxNum) {
        window.clearTimeout(ft);
        countStatus3 = -1;
        document.getElementById('btnFillTable3').value = "Get data...";
        document.getElementById('btnFillTable3').disabled = false;
        window.status = "Getting data from web server... done.";
    }
    document.getElementById('txtcountStatus3').value = countStatus3;
}

The code above calls into the page method shows an alternative way, it uses an anonymous JavaScript function definition. The function populateTable() is executed continuously with the following code:

ft = window.setTimeout("populateTable()", 250);

This means that the function is repeatedly executed every 250 msec. When the web server returns a counter value of 50 (which resembles 100%) the callback stops:

window.clearTimeout(ft);

The next time the button is clicked, the progressbar is cleared and a message is displayed:

function ClearProgressBar() {
    if (countRepeat3 == 1) {
        alert("Hey, you've already run this once! :-)");
    }
    else {
        alert("Hey, you've already run this " + countRepeat3 + 
          " times! :-)");
    }
    document.getElementById("divProgressBar2").style.background = "white";
    document.getElementById('txtPerc3').value = "";
    countStatus3 = 0;
}

Ajax.NET Professional

Here, the callback is initiated using a server-side button:

<asp:Button ID="btnFillTable3" OnClientClick="populateTable();
    return false;"...

The function populateTable() is executed:

var countStatus3 = 0;
var countRepeat3 = 0;
var ft;
var iMaxNum = 49;
function populateTable() {
    window.status = "Getting data from web server... ";
    document.getElementById('btnFillTable3').value = "Working...";
    document.getElementById('btnFillTable3').disabled = true;
    // clear div if already run once
    if (countStatus3 == -1) {
      ClearProgressBar();
    }
    AjaxNETSample._Default.UpdateCounter(countStatus3, 
      postPopulateTable);
    // continiously execute method....
    ft = window.setTimeout("populateTable()", 250);
    if (countStatus3 ==  iMaxNum) {
        window.clearTimeout(ft);
       countStatus3 = -1; // for next click
       document.getElementById('btnFillTable3').value = 
         "Get data...";
       document.getElementById('btnFillTable3').disabled = false;
       window.status = "Getting data from web server... done.";
     }
    document.getElementById('txtcountStatus3').value = countStatus3;
}

This calls the web page method UpdateCounter():

[AjaxPro.AjaxMethod]
public int UpdateCounter(int iCounter)
{
    System.Threading.Thread.Sleep(100);
    iCounter++;
   return iCounter;
}

Each time the callback returns, it updates the progressbar and the percentage textbox:

function postPopulateTable(result) {
    document.getElementById("divProgressBar2").style.backgroundColor =
      "red";
    document.getElementById("divProgressBar2").style.width = result.value*5
      + "px";
    countStatus3 = result.value;
    document.getElementById('txtPerc3').value = countStatus3*2 + "%";
    if (countStatus3 == (iMaxNum + 1)) {
        countStatus3 = -1;
        countRepeat3++;
    }
}

The function populateTable() is executed continuously until the web server returns it's ready with its job and clearTimeout() stops the callbacks. Like the other examples, when clicking the button again, the progressbar and percentage textbox are initiated to their initial values.

That was it regarding the code details; now let's compare these three frameworks and then finally look at the feature-comparing table.

Framework Comparison

I'd like to discuss a few observations now in comparing the three frameworks we've been looking at in detail.

Multiple Callbacks on a Page

The samples I've included use for each example a button, be it of type HTML, asp:Button, or anthem:Button. If you click on every button within short intervals, multiple callbacks are executed which could influence each other. And yes, they do, unfortunately. The effect varies with each framework though.

The first rule to consider is when using multiple callbacks that fire simultaneously, don't use alerts. They will kill your Ajax functionality that is running at that moment in the background. In most of the frameworks and browsers, using alerts stops the JavaScript engine from continuing. I haven't done detailed tests yet, but from what I've seen I'd say it's simply better to avoid using alerts and use a <div> or label controls to indicate messages, warnings, and errors.

The second thing to consider is to not using framework specific controls if you don't need to, they could well be influenced by a callback that wasn't meant to update other controls on the page. For example, Anthem.NET includes for every callback the complete collection of anthem:xxx controls, and if you have them set to automatic update after a callback they will be reset to their initial viewstate value.

Capability to Reduce Development Time?

For all three frameworks, it is fairly easy to integrate them into web pages, whether they already exist or are being created from scratch.

For Atlas, adding Ajax functionality the way I showed is fairly simple, but it doesn't reduce development time. It is however worth the price as the results in terms of application performance improvements and user-friendliness are in most cases surprising. But there's more, Atlas has the capability to Ajax-ify any area by using the UpdatePanel. A web page that contains a GridView is wrapped into the UpdatePanel control and that's about it. The use of web services makes it easy to add Ajax functionality to an existing page.

With Anthem.NET you have the ability to utilize a special control collection that is derived from the normal asp:xxx controls but adds additional useful functionality. This doesn't really reduce development time however, but it feels exactly like normal ASP.NET-like web application development and that means it's easy to integrate. Anthem.NET provides complete source control, which can be an advantage in those cases where the framework needs to be extended with extra functionality.

Finally, Ajax.NET Professional doesn't provide a way to use web services nor does it provide a special control collection. It does however impose less load on the web server, which can have its benefits in some web scenarios.

web.config Changes and their Implications

Each framework requires some special settings in the web.config file. Both Anthem.NET and Ajax.NET Pro need simple settings while Atlas requires additional sections. It is important to follow the instructions that are provided by each framework, and in the case of Atlas you should copy the relevant sections to your web.config cautiously.

Ajax Framework Comparison Table

The following table provides a summary of support is provided by the various frameworks I've been using in these articles.

FeatureMS AtlasAnthem.NETAjax.NET
IDE support:      
VS.NET 2003 - Tick Tick
VS.NET 2005 Tick Tick Tick
ASP.NET v1.1 - Tick Tick
ASP.NET v2.0 Tick Tick Tick
Pre callback JavaScript Tick Tick Tick
Post callback JavaScript Tick Tick Tick
Tight integration in the page lifecycle Tick Tick -
Release Name March Release Anthem-1.0.0 Ajax.NET Pro for .NET v2.0
More Information http://atlas.asp.net http://sourceforge.net/projects/anthem-dot-net http://dotnet2.schwarz-interactive.de/

There is considerable cross-browser support. When I first started this article, I prepared an extended version of this table which indicated which of the samples I've presented work on each browser, but over the last couple of months support has improved, which means all of the samples work with all three frameworks on all of the following browsers:

  • IE6+ (PC)
  • IE7 Beta2 Preview
  • Mozilla FireFox 1.5+ (PC)
  • Safari 1.3 and 2.0+ (Mac OS X)

Note: For the examples to work well, FireFox and Safari need anonymous access in IIS 6, which can complicate things in the case of intranet development.

Note 2: The example worked in FF after I changed the following JavaScript function call definition:

..OnClientClick="preCBF_btnFillTable1();" 

into

..OnClientClick="preCBF_btnFillTable1(); return false".

Conclusion

In this two part article I have discussed Ajax with respect to ASP.NET development. I've shown you three of the popular Ajax frameworks that support ASP.NET web application development. I've discussed where each framework differs from the others and what their strong and weak points are. Several examples were used to show how to integrate the various frameworks into the .your code base using each of the frameworks.

This set of articles has provided a good idea of what it means to have Ajax support in your development, and also where you can apply this exciting new way of updating specific controls or areas in your web pages. Lastly, I presented a table that provides a summary of what has been discussed in the articles so that you can easily determine which framework will work best for you.

Founders at Work



Add your comments

Please keep your comments relevant to this blog entry: inappropriate or purely promotional comments may be removed. To add hyperlink, please follow this example: "your link text":http://your.link.url