To me, you canât get too far into the whole Web2.0/Ajax/Mashup/Whatevr discussion without coming up with a method of handling long running web requests. Yes, AJAX is about providing a responsive UI while youâre posting back to the server, but the more we begin to mash together all these remote webservice calls, fetch xml data to display and perform lots of real work in our web applications, weâre going to have to go beyond AJAX and use real-life honest to goodness asynchronous method invocation on the server.
What? I thought AJAX was Asynchronous?
In a sense, AJAX isnât really asynchronous at all when it comes to HTTP requests. An AJAX web request is a synchronous web request just like any other. All AJAX solutions really are doing is using the browserâs built in threading (via JavaScript) to make multiple web requests for you, and then updating the HTML when the server responds. These are really client-side hat-tricks, and will only get you so far and requires that the data youâre fetching on the servers is readily available. What happens when the server doesnât respond for ten minutes or even more?
You will run into problems with page requests that bump up against ASP.NETâs ScriptTimeout (which is set at 90 seconds by default). AJAX or no AJAX, if your web method takes longer than your ScriptTimeout, youâre going to have problems. You could try to guess the length of time that this will take and set your script timeout to some really large value, but here youâre just guessing what will work, and you run into other problems as well. This article here nicely describes the general problem youâre faced with with requests timing out.
Consider the following Code
protected void Button_Click(object sender, EventArgs e) { int totalSeconds = 5; Thread.Sleep(totalSeconds * 1000); Label2.Text = "Our Long Running Method finished at " + DateTime.Now.ToLongTimeString() + " and took " + totalSeconds + " seconds to complete";
}
If you crank your RequestTimeout down by adding this line to the Web.Config file:
<httpRuntime executionTimeout="1"/>
⦠youâll see this screen, AJAX or no AJAX:
So How Do I Build Truly Asynchronous Web Applications?
As far as I can see it, and you should never trust me, but you have two good choices for making applications that can properly handle long running requests:
1) Use a message queue. This is often a good choice where you need a guarantee that the process completed. You could use MSMQ or something else to make sure youâve got the ability to reliably process requests on the server.
2) Use Asynchronous Method Delegation on the server, create a polling mechanism let the user know when the method has finished. This âFire and Forgetâ method of server side processing is a good, simple, straightforward method of doing work on the server. In fact, the most basic method of doing this is so simple, that you can implement this with very little code:
/// <summary> /// The Long running method async call. /// </summary> private IAsyncResult LongRunningMethodAsync() { LongRunningMethodDelegate longRunningDelegate = new LongRunningMethodDelegate(LongRunningMethod); IAsyncResult ar = longRunningDelegate.BeginInvoke(new AsyncCallback(LongRunningMethodCallback), null); return ar; }
/// <summary> /// The long running method callback. /// </summary> private void LongRunningMethodCallback(IAsyncResult ar) { AsyncResult aResult = (AsyncResult)ar; LongRunningMethodDelegate longRunningDelegate = (LongRunningMethodDelegate)aResult.AsyncDelegate; int totalSeconds = longRunningDelegate.EndInvoke(ar); }
/// <summary> /// The long running method. /// </summary> private int LongRunningMethod() { Random rand = new Random(Guid.NewGuid().GetHashCode()); int mseconds = rand.Next(90000, 100000); Thread.Sleep(mseconds);
YES! Ajax is a very important piece of the puzzle, and solves many of the problems faced with creating responsive web User Interfaces. In fact, the combination of AJAX using something like ATLAS with Asynchronous Method Delegation can really add up to some powerful stuff. Iâve put together a small sample application that shows how to use ATLAS to create a progress bar that shows the status of the long running method, called using Asynchronous delegation on the server.
This application uses ATLAS to provide the AJAX user interface, and presents three link buttons that call methods both asynchronously and synchronously on the server with the ScriptTimeout property set really low to simulate long running request problems. It also uses a cool feature of ATLAS, the TimerControl, to provide the polling code necessary to update the UI and show a progress bar. Download the code here to try it out for yourself. Iâve had to rip out the ATLAS script stuff because of the ATLAS eula, but download ATLAS, and copy the Microsoft.Web.Atlas.dll to the bin directory, and the ATLAS Scripts to the ScriptLibary directory and you should be able to experiment with this code.
Further Reading
Fritz Onionhas a great MSDN article titled Use Threads and Build Asynchronous Handlers in Your Server-Side Web Codeand also mentions that the above solution actually uses a thread from the thread pool, so it wont help with issues of scaling an application that has a lot of long running operations. To get around this youâd want to create your own threads, pool and manage them by hand, something Iâm not comfortable doing on my own . But if you need to scale an application AND provide lots of long running processes at once, youâll want to look there.