Click here to Skip to main content
Click here to Skip to main content

Processing Long Running Tasks With Asynchronous Handlers and XMLHTTP

, 17 May 2005
Rate this:
Please Sign up or sign in to vote.
This article shows you how to use async handlers along with XMLHTTP to process long executing tasks in ASP.NET.

Sample Image - main.jpg

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:

/*
Class Definition for System.Web.UI.Page
*/
public class Page : TemplateControl, IHttpHandler

System.Web.UI.Page hierarchy

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:

  1. Using the System.Threading.ThreadPool.
  2. Using a custom delegate and calling its BeginInvoke method.
  3. 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:

Async request object collaboration

  1. As soon as the handler receives a request, it creates an object of type AsyncRequestResult.
  2. Using this object as a constructor parameter, the handler then creates an object of type AsyncRequest.
  3. 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:

/// <span class="code-SummaryComment"><summary>
</span>
/// Uses the IAsyncResult object to call a web service and writes
/// back the response to the caller
/// <span class="code-SummaryComment"></summary>
</span>
public void Process()
{
    try
    {
        // Get the zip code from the AsynRequestResult object
        string strZip = Result.AsyncState as string;
        int zipCode = Int32.Parse(strZip);

        // Get the weather information
        string message = Result.GetWeather(zipCode);

        // Write back to the client
        Result.Context.Response.Write(message);
    }
    finally
    {
        // Tell ASP.NET that the request is complete
        Result.Complete();
    }
}

The actual call to the weather web service under the AsyncRequestResult.GetWeather method looks like:

///<span class="code-SummaryComment"><summary>
</span>
/// Gets the current weather information based on a US Zip code
/// <span class="code-SummaryComment"></summary>
</span>
/// <span class="code-SummaryComment"><param name="zipCode">City zip code</param>
</span>
/// <span class="code-SummaryComment"><returns>Location name along with current temperature.
</span>
///               Empty string otherwise.<span class="code-SummaryComment"></returns>
</span>
public string GetWeather(int zipCode)
{
    string message = "";

    try
    {
        // Call the web service
        ExtendedWeatherInfo info = 
            weatherService.GetExtendedWeatherInfo(zipCode);

        // Format the message
        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:

/*
    Creates a XMLHTTP async-call to an ASP.NET async handler
*/
function postRequest(url)
{
    var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    
    // '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 += "<p>" + response + "</p>";
                
                stopProgressBar();
            }
        }
    
    // Send the actual request
    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.

Making the UI responsive while executing a async call

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

Full request to handler and UI response

  1. An XMLHTTP object is created when the user clicks on the Check Weather button.
  2. This object creates an async (non-blocking) request to weatherchecker.ashx.
  3. A temp callback is attached to the object to handle the response from the handler.
  4. Another JavaScript function is called to start the progress bar and display the 'Processing request...' text.
  5. Whenever the handler is finished executing the call to the web service, a response is generated back to the client's temp callback.
  6. 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:

Result from call

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:

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

Share

About the Author

Javier Lozano
Web Developer
United States United States
Javier is a consultant specializing in ASP.NET, system architecture, and training. He's also a MCSD .NET and a co-founder of the Iowa DotNET Users Group. Recently, Javier was awarded the Visual Developer ASP.NET MVP award from Microsoft.
 
On his blog you can find posts on ASP.NET, architecture, design patterns, XML and just recently, Indigo. Javier enjoys giving back to the community by speaking at user groups, local/regional .NET events, being active in forums and by writing articles for Code Project.
 
In his spare time, Javier enjoys spending time with his wife, newborn son, two golden retrievers and writing about himself in third person.
 
Click here to read Javier's blog.

Comments and Discussions

 
QuestionIs it possible to send the http context from the requested page to the handler? PinmemberTravelthrprog24-May-10 12:24 
AnswerRe: Is it possible to send the http context from the requested page to the handler? PinmemberJavier Lozano24-May-10 12:29 
GeneralRe: Is it possible to send the http context from the requested page to the handler? PinmemberTravelthrprog25-May-10 3:39 
QuestionA Problem Pinmembernis2722-Jun-09 11:47 
AnswerRe: A Problem PinmemberJavier Lozano22-Jun-09 11:53 
QuestionRe: A Problem Pinmembernis2722-Jun-09 12:35 
QuestionRe: A Problem Pinmembernis2723-Jun-09 8:55 
AnswerRe: A Problem PinmemberCoperNick2-Mar-10 6:22 
GeneralI want to call Multipe Webservice Function PinmemberMember 293710310-Feb-09 21:08 
GeneralIs there any Timelimit PinmemberNewwbie10-Apr-07 23:44 
GeneralNon IE AJAX / XMLHTTP PinmemberKiller Shrike16-Mar-07 14:49 
GeneralRe: Non IE AJAX / XMLHTTP PinmemberJavier Lozano16-Mar-07 16:22 
GeneralRe: Non IE AJAX / XMLHTTP PinmemberKiller Shrike17-Mar-07 16:45 
GeneralRe: Non IE AJAX / XMLHTTP PinmemberMcSdwarken12-May-07 2:39 
QuestionNon Blocking ? [modified] Pinmemberpmadhav15-Jul-06 11:09 
AnswerRe: Non Blocking ? [modified] PinmemberJavier Lozano7-Jul-06 12:10 
GeneralRe: Non Blocking ? Pinmemberpmadhav19-Jul-06 23:37 
GeneralRe: Non Blocking ? Pinmemberpmadhav119-Jul-06 22:15 
QuestionHow to stop the process PinmemberMetxtli228-Apr-06 15:47 
AnswerRe: How to stop the process PinmemberJavier Lozano1-May-06 17:09 
QuestionFiring multiple requests to Web-Service PinmemberElango Chidambaram20-Mar-06 5:42 
AnswerRe: Firing multiple requests to Web-Service PinmemberJavier Lozano21-Mar-06 17:10 
GeneralUsing AsyncState Pinmemberkyoseix13-Feb-06 7:34 
GeneralRe: Using AsyncState PinmemberJavier Lozano13-Feb-06 16:08 
NewszumiPage for ASP.NET PinmemberAmir L.21-Dec-05 13:49 
GeneralRe: zumiPage for ASP.NET PinmemberJavier Lozano21-Dec-05 18:26 
GeneralAnother way PinsussVinod C D22-Sep-05 4:39 
GeneralRe: Another way PinmemberJavier Lozano23-Sep-05 14:27 
Generalnot working Pinsussmahendra singh bisht24-Aug-05 5:44 
Generalnot working Pinmembermahendra singh bisht24-Aug-05 5:42 
GeneralExcellent Article! Pinmembersheppe23-Aug-05 12:41 
GeneralSecond Time don't send *.ashx page PinmemberJaimirG7-Jul-05 14:50 
GeneralWeather Service Sign Up Operational Again PinmemberJavier Lozano16-Jun-05 17:35 
QuestionTimeout ??? PinmemberFayez Mutairi22-May-05 9:15 
AnswerRe: Timeout ??? PinmemberChucklesHB31-May-05 9:37 
GeneralRe: Timeout ??? PinmemberSpiff Dog6-Dec-05 18:08 
GeneralRe: Timeout ??? PinmemberChucklesHB8-Dec-05 4:44 
QuestionWhat is the difference to BeginInvoke PinmemberRonBurd18-May-05 7:26 
AnswerRe: What is the difference to BeginInvoke PinmemberJavier Lozano18-May-05 9:12 
GeneralPossible alternative on the client side. Pinmembervarnk18-May-05 3:45 
GeneralRe: Possible alternative on the client side. PinmemberJavier Lozano18-May-05 4:48 
GeneralResponse in a different page PinmemberRonBurd17-May-05 8:48 
GeneralRe: Response in a different page PinmemberJavier Lozano17-May-05 9:37 
GeneralRe: Response in a different page PinmemberRonBurd17-May-05 11:23 
GeneralImplement in Datagrid Pinmembervipinjose200415-May-05 18:45 
GeneralRe: Implement in Datagrid Pinmembervipinjosea7-Jun-05 22:21 
GeneralNice article Pinmemberrasputin123412-May-05 17:55 
GeneralBrowser compatibility PinmemberDflare12-May-05 14:45 
GeneralRe: Browser compatibility Pinmembersunnychess200112-May-05 22:01 
GeneralRe: Browser compatibility PinmemberJavier Lozano13-May-05 4:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150129.1 | Last Updated 18 May 2005
Article Copyright 2005 by Javier Lozano
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid