
Introduction
Processing long running tasks (i.e., SQL query execution, Web Services calls, etc.) has always been an important feature for high demand web applications. One problem these applications face is that of keeping the client UI responsive as the task executes.
Many sites, like Expedia, Travelocity etc. use intermediate 'Please Wait...' pages to work around the problem. Other sites, like Google Maps use client-side features such as XMLHTTP to make such requests without moving the user from the current page. The purpose of this article is to show how to use XMLHTTP along with ASP.NET to make the end user experience a bit more tolerable.
Background
Architecturally speaking, a key feature of ASP.NET is its objects have a short lifespan. This is extremely important to high demand web sites because it allows the application to execute quickly and efficiently and still be able to maintain a high level of concurrent users. The key factor behind keeping an ASP.NET web site responsive is to be aware of the framework constructs that control page execution.
A lot of developers know that to create a simple web page in ASP.NET one must use the System.Web.UI.Page class. However, some of them might not be aware that there are other ways to handle requests made to the application. This is where System.Web.IHttpHandler and System.Web.IHttpAsyncHandler interfaces come into play.
IHttpHandler and IHttpAsyncHandler: A Quick Look
All request execution in ASP.NET happens through the System.Web.IHttpHandler interface. If you look at the object diagram of the System.Web.UI.Page class, you can see that it inherits from the System.Web.UI.TemplateControl and implements the System.Web.IHttpHandler interface. The class definition and object hierarchy looks like this:
public class Page : TemplateControl, IHttpHandler

The IHttpAsyncHandler interface inherits from IHttpHandler and defines two extra methods, BeginProcessRequest and EndProcessRequest respectively. These methods make up the mechanism needed to handle asynchronous calls within ASP.NET.
For this type of scenario, it is better to use the IHttpAsyncHandler rather than a Page object because of all the extra work (child control rendering, event handler notification, etc.) the Page performs per request. For more information on IHttpAsyncHandler, please see the MSDN documentation.
A Poor Man's Guide to Threading in ASP.NET
There are three simple ways you can accomplish threading within your ASP.NET application:
- Using the
System.Threading.ThreadPool.
- Using a custom delegate and calling its
BeginInvoke method.
- Using custom threads with the aid of
System.Threading.Thread class.
The first two methods offer a quick way to fire off worker threads for your application. But unfortunately, they hurt the overall performance of your application since they consume threads from the same pool used by ASP.NET to handle HTTP requests. In other words, if you invoke five pool/delegate threads within a request, your application will only have 20 available threads remaining in its pool (by default, ASP.NET gives every application 25 worker threads). The way to get around this problem is to use the third option since the threads created are not part of your application's pool.
If you would like to read more on threading in ASP.NET, please see the References section.
Stepping Through the Code
The example used with this article is that of a simple weather service. The UI allows the user to enter US Zip codes to check current weather condition of cities. The reason why I chose a web service call is because it gives a great 'real world' example on how to use the asynchronous capabilities of ASP.NET and XMLHTTP.
When a user selects an entered zipcode from the list and hits the Check Weather button, two async requests are created, one to the weather checker handler and the other to the web service. A DHTML progress bar is used to keep the user 'entertained' while this process executes. Once a response is received by the client, the progress bar is stopped and the UI updated.
The main class behind this example is the AsyncTaskHandler class. This class is mapped to an .ashx file so ASP.NET can hook up the request chain. This class implements two interfaces the IHttpAsyncHandler, mentioned earlier, and the System.Web.SessionState.IRequiresSessionsState interface that is used to tell ASP.NET that this handler has access to session state. The class then uses two classes AsyncRequestResult and AsyncRequest to process the request.
AsyncRequestResult implements the System.IAsyncResult interface so ASP.NET can call the appropriate methods necessary to perform a call back. The AsyncRequest class is used to house a call to an external weather Web Service and write back the response to the waiting client. The collaboration between the objects can be seen by the following diagram:

- As soon as the handler receives a request, it creates an object of type
AsyncRequestResult.
- Using this object as a constructor parameter, the handler then creates an object of type
AsyncRequest.
- Finally, the handler creates a worker thread of type
System.Thread.Thread and uses the Process method of AsyncRequest and returns the created AsyncRequestResult back to ASP.NET and a response to the client.
Most of the core logic takes place within the AsyncRequest.Process method. Within this method, the associated AsyncRequestResult object is used to make a call to the weather information web service and to return an HTML snippet back to the client. The method looks as follows:
public void Process()
{
try
{
string strZip = Result.AsyncState as string;
int zipCode = Int32.Parse(strZip);
string message = Result.GetWeather(zipCode);
Result.Context.Response.Write(message);
}
finally
{
Result.Complete();
}
}
The actual call to the weather web service under the AsyncRequestResult.GetWeather method looks like:
public string GetWeather(int zipCode)
{
string message = "";
try
{
ExtendedWeatherInfo info =
weatherService.GetExtendedWeatherInfo(zipCode);
message = string.Format("<h2>{0} - {1}" +
"</h2>Current Temperature: {2}a<br>Feels Like: {3}.",
zipCode.ToString(), info.Info.Location,
info.Info.Temprature, info.Info.FeelsLike);
}
catch
{
message = "An error was encountered while calling web service.";
}
return message;
}
Now that you have a quick overview of how the code works, let's see how the client creates the request and handles the response.
Using XMLHTTP Within IE
To make an HTTP request programmatically through JavaScript, you need to use XMLHTTP. For quite some time, Microsoft had bundled a version of this technology within their MSXML parser. To create a JavaScript object that binds to this feature, you do the following:
var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
This function will make a full asynchronous request to a URL and attach a callback function:
function postRequest(url)
{
var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.Open("POST", url, true);
xmlhttp.onreadystatechange =
function ()
{
if (xmlhttp.readyState == 4)
{
var response = xmlhttp.responseText;
divResponse.innerHTML += "<p>" + response + "</p>";
stopProgressBar();
}
}
xmlhttp.Send();
}
From here, while we wait for the async handler to execute the long processing request, we show the users a simple little progress bar showing them that their request is being processed.

The following diagram shows how the execution of the request from XMLHTTP takes place:

- An
XMLHTTP object is created when the user clicks on the Check Weather button.
- This object creates an async (non-blocking) request to weatherchecker.ashx.
- A temp callback is attached to the object to handle the response from the handler.
- Another JavaScript function is called to start the progress bar and display the 'Processing request...' text.
- Whenever the handler is finished executing the call to the web service, a response is generated back to the client's temp callback.
- The temp callback is executed in the client, the response text is set to a
<div>, and the progress bar is stopped.
The final result from this process looks like:

Conclusion
Having the ability of executing long running tasks asynchronously is a huge benefit for any web application regardless of size. I hope that this article shows developers an alternate way of tackling this design problem. Also, I hope that developers are more conscious when making decisions to add threading to their ASP.NET applications.
Please feel free to make any comments or suggestions to this article by using the forums below.
Reference
During my writing of this article, I used the following resources:
| You must Sign In to use this message board. |
|
|
 |
|
 |
Hi,
Thanks for the nice article.
Currently, i'm working on an application, which loads some calculated data from 3rd party providers. i'm using serverside C# 3rd party API to get the data.
the problem is that it takes long time 20 seconds to get the response. i'm firing XMLHTTP call to my ASPX page to get the text output and i write it to DIV, but many of the user have complained that wen they come on the page they cant do anything while it is retrieving the calculated data. so if they want to navigate to another page while XMLHTTP is getting the data they can not.
Can you please tell me how can i do this ?
Thanks, Nish.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Sorry for making it sound complicated. here is simpler version.
1. on my home page(Home.aspx) - onload() event i create XMLHTTP(Async=true) request to another of my web page(Getdata.aspx). result is some calculation of the data for the user. 2. Home.aspx, also has other links on the page, so whle my XMLHTTP request is waiting for response, if user click on any of the links. i.e. my profile then nothing will happen until i get response back from the server.
but i want users to navigate away if they want to, but right now they can not.
Thanks for your reply.
Thanks, Nish.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
following is the more simpler version ------------
Sorry for making it sound complicated. here is simpler version.
1. on my home page(Home.aspx) - onload() event i create XMLHTTP(Async=true) request to another of my web page(Getdata.aspx). result is some calculation of the data for the user. 2. Home.aspx, also has other links on the page, so whle my XMLHTTP request is waiting for response, if user click on any of the links. i.e. my profile then nothing will happen until i get response back from the server.
but i want users to navigate away if they want to, but right now they can not.
Thanks for your reply.
Thanks, Nish.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi Javier,
Thanks for your Article. It is really helped me to know the iHttpHandler. I have one Quick Question. You are calling GetWeather function as a WebService. In the same Manner once i got the result from GetWeather, i need to call one more web service. Please can you tell me how to make it.
Thanks, Shiva
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi, I had added a delay after calling the webservice for an hour...It didn't return me anything as result..Couldn't figure out the reason..So can't i use this if the webservice may take hours to return me the result? Appreciate any earliest reply. Thanks
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
Replace the postRequest function with:
/* Creates a XMLHTTP async-call to an ASP.NET async handler */ var xmlhttp = null; function postRequest(url) { //var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); createRequest(); // 'true' specifies that it's a async call xmlhttp.open("POST", url, true); // Register a callback for the call xmlhttp.onreadystatechange = function () { if (xmlhttp.readyState == 4) { var response = xmlhttp.responseText; divResponse.innerHTML += "" + response + " "; stopProgressBar(); } } // Send the actual request xmlhttp.send(null); } function createRequest() { try { xmlhttp = new XMLHttpRequest(); } catch (trymicrosoft) { try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (othermicrosoft) { try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (failed) { xmlhttp = null; } } }
if (xmlhttp == null) alert("Error creating request object!"); }
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
|
 |
|
 |
No, thank you for code; very useful.
A couple of questions though; Im implementing something using your example as a guide, and Ive run into a couple of hitches.
Hitch one: It seems like readystatechange for states 2,3, and 4 all get called at the very end right on top of each other.
FF 2.0.0.2: Sat Mar 17 2007 18:25:49 GMT-0700 (Pacific Daylight Time): Run Clicked Sat Mar 17 2007 18:25:49 GMT-0700 (Pacific Daylight Time): Client is initializing (1). Sat Mar 17 2007 18:26:09 GMT-0700 (Pacific Daylight Time): Server is processing (2). Sat Mar 17 2007 18:26:09 GMT-0700 (Pacific Daylight Time): Server is finalizing (3). Sat Mar 17 2007 18:26:09 GMT-0700 (Pacific Daylight Time): Process is complete (4).
Opera 9.10: Sat, 17 Mar 2007 18:41:28 GMT-0700: Run Clicked Sat, 17 Mar 2007 18:41:48 GMT-0700: Server is finalizing (3). Sat, 17 Mar 2007 18:41:48 GMT-0700: Process is complete (4).
(IE 6.0 gives me a Permission denied error on the POST command and halts)
Is there a way to force the Async caller to send onchange statuses as they occur rather than all at the end?
Hitch 2: Im asigning Context.Response.Write to a delegate to write to as processes run. On the object side i see the delegate being exercised, but the Response doesnt write back to the clien asynch -- it all gets read out at the end.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
There should be
xmlhttp.send('');
instead of
xmlhttp.send(null);
Otherwise it returns "HTTP/1.x 411 Length Required" error in FireFox browser.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi, This a very useful article. Is there a way to acieve the same functionality with the Web UI not locking up. Let me illustrate the point.
Summary: I need my application to be truly non blocking, it is ok for me to lose the results of the initial request.
Details: I took the sample application : Added a Button (Server control) on default.aspx, lets called it Button1.
Added a Response.Redirect ("http://www.codeproject.com") on the code behind in the click event of the button.
1. Clicked on the Check Weather button (the request to the Weather service is in progress now) 2. Clicked on Button1 (when step 1 was still in progress) 3. The application does not take any input Looks like the main page is locked up till the Control is returned from the Weather Service. (I guess it is got to do with the WaitHandle AsyncWaitHandle.)
Appreciate your feedback
Thanks, PMadhav
-- modified at 0:12 Thursday 6th July, 2006
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Sorry it's taking me this long to answer, I've been quite busy at work and I haven't had time to check my articles.
Let me look into this issue and I will let you know what I find out. I will post my results to this thread.
Thanks for the question!
~Javier Lozano Microsoft MVP - ASP.NET
-- modified at 17:10 Friday 7th July, 2006
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi Javier, Thanks for you reply and taking the time to look at the issue. Really Appreciate it. Looking forward to your post Thanks Again
PMadhav
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi Javier, Just wondering if you had any clues on this so that I can research. Sorry for bothering you. Thanks, PMadhav
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi there,
Excelent article!!
I have a question... What is the best way, if it exist to stop the process?
I have a page that use a similar code, but the process is to large so I'm looking for some method to stop it
Any comment or suggestion is good!!
Thanks in advance
Metxtli
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
Hmmm...you will have to keep a reference (whether it thread id, name, etc.) to the thread that's executing the request. Then make another request to a handler/page to kill it.
Sorry for the delay on the response, been quite busy at work/home.
~Javier Lozano
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
My question is just an extension of the previous one asked here in the comments section.
Can the AsyncCallback and the extraData be manipulated directly? Instead of passing in parameters in the query string (in this case as you are passing zip-code in the query string), how about sending in parameters as complex objects for a web service? Can I set the call back and extraData object parameters directly while calling an .ashx file programatically?
And how about if I select multiple cities or zipcodes and I want to loop through all the zipcodes and display all the results at once instead of doing one by one? I know we can define a array of ManualResetEvents and waitall for all to complete. How to set that here and check in the callback?
Any thoughts?
Elango.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Elango Chidambaram wrote: Can the AsyncCallback and the extraData be manipulated directly?
Not through the model I present because they're used internally by the IHttpHandler implementation. Recall that the asynch call happens after a new thread is created from the initial XMLHTTP request. One thing you could try and do is use something like AJAX.NET or Anthem.NET to gain access to the objects in your solution.
~Javier Lozano
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I noticed in the Process() method, result.AsyncState is used to get the zip code. What if you need to get many pieces of information passed to the GetWeather() method? Can multiple things be passed into the AsyncState, just like how you can get multiple things from context.Request[]? Or do you have to define your own way of sending through multiple parameters (i.e. delimited lists, arraylists, etc.).
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
The AsyncState proopert allows you to set a custom object for your request. If you need to pass more info (besides a zip code) such as an ArrayList, Hashtable, or custom data type you will use this object for doing that. The thing about it this property is that you need to cast it back to the correct type for your code to use it.
Does this help you out?
~Javier Lozano
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
The purpose of my article is to show developers another way to tackle a common problem faced by web applications. As for the product you mention, I know nothing about it so I can't say anything on its ability to solve the problem.
~Javier Lozano
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
Yep, that pattern will work as well. The reason why I did it my way it's because it eliminates that intermediate waiting page.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
i downloaded code project in my computer but it is not working it is showing that
An error was encountered while calling web service
is i have to add some extra functionality to run this project because i donot know webservices
reply as soon as possible
mahendra singh bisht
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
|