Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

COMET (or Reverse AJAX) based Grid Control for ASP.NET Web Applications - Scalable, High Performance and Low Latency Grid Control

0.00/5 (No votes)
1 Apr 2009 9  
A COMET/Reverse Ajax based Web Grid Control, which can be used in ASP.NET web application. This control posts the updates to the client based on Server side event(s) thereby reducing network round trips.

Introduction

Better than my words, Wiki's explanation is worth mentioning here:

"Comet is a programming technique that enables web servers to send data to the client without having any need for the client to request it. It allows creation of event-driven web applications which are hosted in the browser."

As an example, consider you have a Grid/Table in your web application. This grid displays dynamic data (say stock quote or portfolio details). You would like to display this ever-changing data in a grid at the client's browser. However, you do not want the page to get refreshed every second. Also, you aren't interested in time-polling (every second or two) using AJAX as this will stall your sever with increase in number of clients. Your interest is to display this dynamic content, but update the client only when it is necessary (i.e., when there is a change in the grid data) avoiding unnecessary communication between client and server. The answer to the situation is 'Use this COMET based Grid control' in your web application.

Why COMET based Grid Control is Useful?

Consider the above stated situation. The easily available choice is to use regular timer based AJAX calls to the server. This will make calls to the server based on timer expiry (say one or few seconds). The disadvantages in this approach are: 

  1. Unnecessary calls are made to the server, even though there may be no update. 
  2. With number of clients increasing, server may get overloaded exponentially, i.e., number of clients is directly proportional to server load. This stalls the server with a few hundred clients.

To avoid these disadvantages, we need an approach that updates the clients when the data at the server side changes, an event-driven model. Also, we need to update the clients in an asynchronous pattern without blocking ASP.NET threads. This principle is applied in this COMET based Grid control. Hence, if this control is used in your ASP.NET application, then the below advantages are reaped:

  1. Push the data to the clients when the server side data changes, avoiding unnecessary round-trips to clients. The results is: increase in performance of network, IIS server, and your ASP.NET application. 
  2. Asynch handling of clients avoids blocking ASP.NET threads thereby increasing the application's performance significantly. This will be explained in detail in the section 'Explanation of COMET Grid control design'.

This certainly does *not* mean AJAX is bad and COMET is great. AJAX is a great solution pattern to solve certain problems, while COMET is great to solve other set of problems. Using one in the other's place is sometimes a disaster.

Using the Code in your ASP.NET App

Prerequisites

Visual Studio 2008 and .NET 3.5

Quick Demo

To see a quick demo, just open the solution in Visual Studio 2008. Run the application.

Using this COMET Grid Control is an Easy 3 Step Process

  1. Add this control to your project

    How to do this:

    1. Right click Toolbox | Select 'Choose items...'| Click Browse. Then browse to select the downloaded (from first line in this article) assembly (GridControlCometAjax.dll).
    2. From Toolbox, drag and drop the newly added control to your web page.
  2. Add an Asynch handler in your web.config file in the section httpHandlers as below:
    add verb="GET, POST" path="GridControlCometAjax.ashx" 
    	type="BK.Util.GridAsynchHandler, GridControlCometAjax" validate="false"
  3. In your code-behind (say, Default.aspx.cs), add the below line in your 'Page_Load' method:
    protected void Page_Load(object sender, EventArgs e)
    {
       // Your code goes here.  
       // Assuming the control instance's name is GridControlCometAjax1, 
       // add the below line:
       GridControlCometAjax1.LoadControl(this);
    }

Well, that's it. Now start using the control. Whatever you update in this grid control using any method prefixed 'Dyn' will be automatically propagated to all the clients. Additionally, these methods are thread-safe. Hence, you may call these methods from multiple threads.

Let's put down few sample(s), which will help us to get started.

Use-Case 1: How to Initialize

Consider, you want to fill the grid with initial values (and their color), which need to be propagated to all the clients once you are finished - use the below code sample. As usual, code explanation inline.

// Iterate through each item in the grid to fill them with some random values.
for (int Rowitem = 0; Rowitem < 5; Rowitem++)
{
   for (int ColItem = 0; ColItem < 5; ColItem++)
   {
      // Get a random value to put in side each cell
      double ValueToModify = randomNo.NextDouble();

      // Update the Grid with the Random value we got just above.
      GridControlCometAjax1.DynModifyTableItem
		(Rowitem, ColItem, ValueToModify.ToString("N2"), false);
      // Update the Grid's text color to be black.
      GridControlCometAjax1.DynModifyTableItemColor
		(Rowitem, ColItem, Color.Black, false);	
   }
}

// Now, we are finished with our initialization.  Send updates to all the clients.
GridControlCometAjax1.DynUpdateAllClients();

Use-Case 2: How to Modify Grid's Content and Propogate to Client Immediately

You would like to update a cell in the Grid view at server side and send an update to the client at once. Fortunately, this is a one-liner.

GridControlCometAjax1.DynModifyTableItem
	(RowToModify, ColToModify, StringToUpdate, true);

 

Note that, in the above line, the last parameter needs to be set to true.

Use-Case 3: How to Modify Grid's Text Color and Propagate to Client

You would like to update the Cell's text color in the Grid view and propagate this change to the client at once.

GridControlCometAjax1.DynModifyTableItemColor
	(RowToModify, ColToModify, Color.Red, true);

There are other useful methods in this Grid control, which may be useful. However, all the dynamic methods (methods connected to the client) are prefixed 'Dyn'.

Performance Results

I performed a stress test using Microsoft's Web Application Stress test tool. A complete report is attached as a downloadable file in the link above. However, an overview is given below. I used 100 threads with 10 sockets per thread, which means 1000 concurrent connections. I used the test application, that updates the clients with two grid controls. Here are the results:

Explanation of COMET Grid Control Design

If you are just interested in using this control, you may skip this section. However, if you are interested to know the design of this control, continue reading.

Firstly, HTTP is a request-response protocol. i.e., Client (potentially from a browser) requests and Server responds. In relationship to this well-known concept, AJAX makes very much sense. An Ajax client (possibly from a browser) makes an XmlHttp request and server responds. However, the difference is the whole web page is not re-initialized (or refreshed), but just the AJAX portion of it. Simple and straight to understand. Now, consider the reverse case, the server updates the clients, whenever it wants to. This is called COMET or Reverse Ajax. Not very easy to digest at first though.

Well, how do we achieve this? Consider a foot ball contest. Foot ball teams wishing to compete register to an organizing authority. Then onwards, the organizing authority keeps posting the Foot ball Teams on any events, such as, Date changes, Venue changes, etc. The same here - Just replace 'Foot ball teams' to browser clients and Organizing authority to Server (hosting your ASP application, which is using this Grid control).

A Simplified Explanation

Consider a client browser making a call to your ASP.NET server. ASP.NET server renders the page based on what you fill in your website's initial page (default.aspx, possibly). As you have an AJAX component (this COMET grid control), an AJAX call is made to the server. Here is what we do differently in COMET compared to regular AJAX call. A regular AJAX call will be processed immediately, but here we mark the call to be pending. Notice, we didn't respond to the client, but hold the connection alive. We do this for any connected client. We wait until-when a server side event happens, say the grid's content changes. When this happens, we complete the previously pending call. If a server event didn't happen for a longer period of time, a maintenance call is made to the clients to keep the connection alive. Otherwise the client browser may timeout our response. This is how COMET has the ability to serve many clients compared to regular AJAX.

After understanding the initial concept, let's dive into specific details on this COMET Grid web control. The below picture outlines the main design of this control.

As in the above picture, first the client browser registers with the server for notifications. The server holds the response to this HTTP request. When an event occurs, such as change in the grid's value, the server completes the request with updated value. The client browser shows up this new update without refreshing the whole page. This is because this is an AJAX request response. If you want to learn more on AJAX request, read 'Reference 3'. The source code below does this task. Explanation inline.

// The below method is called by ASP.NET request thread to begin 
// asynchronous processing for the request.
public IAsyncResult BeginProcessRequest
	(HttpContext Context, AsyncCallback Callback, object ExtraData)
{
   // We get the Query string to figure out the Grid's instance
   string ClientId = Context.ApplicationInstance.Request.QueryString[0];

   // Using the clientId we obtained above, we get the details of the Grid from Multimap
   ResponseDetails respDet = clientDetails.GetFirstItem(ClientId);

   // Create new Asynch result 
   GridAsynchResult asyncResultToAdd = 
	new GridAsynchResult(respDet, Context, Callback, ClientStatus.Updated);
   // Add the Asynch result to the response details
   respDet.AddClient(asyncResultToAdd);

   // This will return the ASP.NET thread to return to thread pool.
   return asyncResultToAdd;
}

Now, some of you may be concerned about the term 'holding the request' used in the above paragraph. Because holding an ASP.NET thread's request is an expensive affair. This is because, we will run out of server resources real soon with increasing clients. This is solved by using a nice interface IHttpAsynchHandler.

As in the above picture, the Clients requests are kept in a pending queue. This frees up the ASP.NET thread to return to the pool. This particular step greatly improves the server performance. When a change is requested on the control (such as change to be posted to client in the grid), we complete the pending client's request. Also, we perform maintenance calls to client if no event occurred for long period of time. The source code below performs this task. This is the method executed by the thread-pool's thread. Code explanation inline.

public static void WorkerThreadProc(object ThreadParam)
{
   // Get the Response details
   ResponseDetails respDetails = (ResponseDetails)ThreadParam;

   // Run in infinite loop (however it has break statement inside)   
   while (true)
   {
       // Remove the first client to update
       GridAsynchResult asyncResult = respDetails.RemoveClient();
                      
      // If there is no more client to update, break and return.
      if (asyncResult == null)
      {
         break;
      }
     // Else, if the client's status is updated, then add it back to Queue and break
     else if (asyncResult.Status == ClientStatus.Updated)
     {
         respDetails.AddClient(asyncResult);
         break;
      }

      // Send an update to the client.
      asyncResult.SetCompleted();	
      }
}

Points of Interest

  1. This control is tested in Internet Explorer. Although, I coded for other browsers, it was not tested in other browsers.
  2. The control uses PUSH instead of polling-pull. This improves server performance.
  3. The functions prefixed with 'Dyn' need to be used to see an update at the client side. These functions are thread-safe.
  4. This control uses IHttpAsynchHandler interface which significantly improves server side performance enabling service to 1000s of clients.
  5. You do not need any special changes to your proxy or firewall settings to support this control.

Important Reminder!

I would like to hear from you guys on your feedback. I would love to hear your detailed feedback, even if you rate 1 or below. So, please do write your messages. Thanks!

References

  1. Reverse Ajax
  2. Comet (programming)
  3. XMLHttpRequest

History

  • Ver 1.0 - 29th March 2009
  • Ver 1.1 - 31st March 2009 - Added Performance Report

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here