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

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:

Unnecessary calls are made to the server, even though there may be no update.

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:

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.

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

Add this control to your project

How to do this:

Right click Toolbox | Select 'Choose items...'| Click Browse. Then browse to select the downloaded (from first line in this article) assembly (GridControlCometAjax.dll).

From Toolbox, drag and drop the newly added control to your web page.

Add an Asynch handler in your web.config file in the section httpHandlers as below:

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.

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.

publicstaticvoid 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
elseif (asyncResult.Status == ClientStatus.Updated)
{
respDetails.AddClient(asyncResult);
break;
}
// Send an update to the client.
asyncResult.SetCompleted();
}
}

Points of Interest

This control is tested in Internet Explorer. Although, I coded for other browsers, it was not tested in other browsers.

The control uses PUSH instead of polling-pull. This improves server performance.

The functions prefixed with 'Dyn' need to be used to see an update at the client side. These functions are thread-safe.

This control uses IHttpAsynchHandler interface which significantly improves server side performance enabling service to 1000s of clients.

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!

About the Author

Comments and Discussions

I would not worry too much about this guy - he just created an account today and immediately voted 1 on 5 best articles of the month (mine included). I suspect he created more then 1 account - I saw other votes at the same time with the same syntax and grammatical errors from the accounts opened today. I also saw something similar happening before

I wish there would be a way to block those guys and remove their voting - they just discourage people who make an effort to share their knowledge.

I would not worry too much about this guy - he just created an account today and immediately voted 1 on 5 best articles of the month (mine included). I suspect he created more then 1 account - I saw other votes at the same time with the same syntax and grammatical errors from the accounts opened today. I also saw something similar happening before I wish there would be a way to block those guys and remove their voting - they just discourage people who make an effort to share their knowledge.

I would not worry too much about this guy - he just created an account today and immediately voted 1 on 5 best articles of the month (mine included). I suspect he created more then 1 account - I saw other votes at the same time with the same syntax and grammatical errors from the accounts opened today. I also saw something similar happening before I wish there would be a way to block those guys and remove their voting - they just discourage people who make an effort to share their knowledge

One of the other messages asked if Step 2 occurs multiple times and your response was 'No'. I do not see how this could be called COMET since all you are doing is using AJAX to hold open a connection and then sending a response when something has changed. This leaves valuable resources open that the server needs. All you are doing is saving yourself the few milliseconds it takes to make a TCP connection to the server and that is it.

In my opinion you cannot roll out the COMET word with the current technology unless you roll your own TCP server and use Flash/Java/Silverlight to make a connection to it. Its not hard to do but rarely needed. I did this with a javascript based game using a java applet stub for the comet(tcp client) piece.

Hello T.D.Brown,
You Wrote: One of the other messages asked if Step 2 occurs multiple times and your response was 'No'
My Answer: Previously, I mis-understood that question to give a different answer. The answer is 'Yes'. I corrected that now.

As in the following reference: http://wise.ajou.ac.kr/~mikael/resources/doc/investigating_comet_bayeux_protocol.doc
IETF is known as the entity for establishing the internet standards. W3C works in tandem with IETF to provide the WWW standards. When it comes to Comet, none of those two bodies has established the standard. In absence of this, Comet is used as an umbrella term for achieving Push from server side. Again, it is not myself, who coined(or created) this umbrella term. It was created/agreed by several industry professionals. You may google to find out evidence for this.

If we agree on this: To answer your specific concern, independent research performed on this COMET style (long polling) suggests that it outperforms traditional polling.

"This analysis shows that for the worst case, when the message rate is high, load and latency for Comet long-polling are identical to traditional polling, and for most cases the load and latency are significantly better than traditional polling. ”
—Greg Wilkins
Ref: http://en.wikipedia.org/w/index.php?title=Comet_%28programming%29&oldid=217077585#Comet

In Summary: the industry-wide accepted technology word for both patterns (Open TCP connection to browser and Long polling) is Comet. The former pattern (TCP connection using flash/silverlight) is used for fast streaming systems. And the later (Long polling) is used for relatively slower event-based systems. Both patterns are very well used in gaming industry - Fast games such as car race uses former pattern, while slower games such as chess uses later pattern. Both patterns have pros and cons. The choice of which COMET pattern to be used in a solution depends solely on problem statement/business case.

This is the article I read and based my understanding of what COMET is since I believe it was the first article of its kind. I read and immediately created a Java version of it for playing around with. If you notice, it doesn't have to recreate a connection back to the server after each request.

After more thought, I was wrong about the time savings you would get to your approach. You would save the connection time as well as any difference in time that your polling ajax app has in between retries. So if you poll every 5 seconds and it takes 20ms to connect then at max you could save 5seconds + 20ms.

I think what you show here is a great example of what could be done to solve such latency issues, but I don't believe it to be called COMET. Long Polling seems to be a better fit as you described above.

Let me say it in another way. If you have to request for data, even if the response is delayed, then it is not COMET. A client should be able to open a connection and just sit and wait for data to be sent to it. This should be able to be done repeatedly without closing the current connection.

Well, Sun's document (official Java guys - sun.com) state that:
Kinds of Comet Connections
When working with Comet, as implemented in Grizzly, you have two different ways to handle client connections to the server:
(1) HTTP Streaming
(2) long-polling

(2) Long Polling:
The long-polling technique is a combination of server-push and client-pull because the client needs to resume the connection after a certain amount of time or after the server pushes an update to the client.

The basic life cycle of an application using long-polling is:

request -> suspend --> data available --> write response --> resume

The client makes an initial request and then suspends the request. When an update is available, the server writes it to the response. The connection closes, and the client optionally resumes the connection.

I have already stated what the original person who coined the term thought it should be and I can now erase any belief that we might actually get something like it in the browser since there are people so intent on faking it. The mere fact that it is called long-polling should immediately make you realize that it is still ajax polling.

You are not the person who should be getting the brunt of this message. It is those that came up with this idea and tried to call it COMET. While it is pretty cool idea it is better to call it something that it is like Long-Polling then use a term to catch peoples eyes.

On a side note... Did you hear that SUN has a battery you can plug into your car's lighter port to convert it into a hybrid?

The average latency worldwide is around 200ms. If you are within USA, you benefit from all the IP exchanges setup in every city and you get around 70ms latency. If the data center is just couple of blocks away from your place, then you might get 20ms.

So, the saving is significant when the frequency of data delivery is high. Say you are getting data from server once per second. Then the saved time is significant. Especially from Australia->USA where the latency is almost 600ms.

But for occasional push, say one push per minute or higher, not much benefit from push technology.

But this does not mean I am discrediting this article. It's is certainly a very good demonstration of push. It does not matter if the sample made shows the best possible scenario for comet.

Let's consider ocassional push, say one push per minute or higher: The alternative to push is pull. i.e., Ajax timer based polling to query server in a pre-determined time interval. So when the AJAX call is made from client side to query the server for any data change (every minute or little higher), the following may happen:

(1) The data may change just after a client's AJAX call completes. This will leave the client un-updated until next AJAX call, say one minute or little higher.

(2) The above-said scenario may happen continually so that some of the clients may miss the beat by one update.

(3) The client may miss few updates, if suppose, multiple updates (ocassionally) happen within the client's wait time. i.e., consider an update happened at 30th second and 45th second and 61th second on the client's clock, where client polls every minute (60 seconds).

(4) Consider, many clients are waiting with the same clock time. Then, we will have server load undistributed. i.e., 1000 clients making a call every minute. Then, there is a period of utter silence (low server load). Then again, 1000 client calls, so on .. so forth.

As I mentioned in the article, I am not saying COMET is the answer to all scenarios. But COMET is good solution when the clients need to be updated purely based on server side events. i.e., Stock quote, weather report are server side events that need to be propogated to clients. Push is the best answer.

Alternatively, AJAX is good solution when the clients need to be updated based on client side events. ie., Auto-Suggest (as in google) is a client side event handling mechanism. In this case AJAX is the best choice.

I am not sure what your project's requirement is. However the options are to use Lightstreamer or similar server to stream. Otherwise, you need to write similar to what I wrote. But this will take time and effort.

That's fine. Don't bother. I was just joking. I mean, not the link thing, but about your univote. I was curious seeing your sudden vote change and wanted to have some fun talk with you. Don't worry, but it was a good sport. I mean no offence though. Just a pass time in my usually tight work schedule. Hope it was funny for you too!