It's been a while since I visited this subject and I felt I needed to cover a very important missing piece - Async web pages which are primarily used as a server performance enhancement. There are two main methods we will be looking at that are used to execute operations asynchronously from web pages:
Page.AddOnPreRenderCompleteAsync() and Page.AddOnPreRenderCompleteAsync().
Part I. Setup.
There is not a lot of setup to do to prepare our pages for asynchronous behavior. In the page directive we just need to specify: Async="true". Below is the page directive for one of my sample pages.
<%@ Page Async="true" Language="C#" AutoEventWireup="false" CodeFile="RegisterAsyncTask.aspx.cs" Inherits="RegisterAsyncTaskPage" %>
We can also set the timeout here for long running transactions. The default is 45 seconds. There are probably very few situations where we would want longer running pages because the user experience would be very poor, but I could see shortening the timeout up a bit using the following declaration in the page directive: AsyncTimeout="20".
Just FYI: I have created a "fake" long running process for this sample as a placeholder for the actual long-running process that would exist in a real project such as a web service or database call.
public static class LongRunner
{
private delegate void
public static IAsyncResult BeginLongRunningTransaction(AsyncCallback cb, object state)
{
return method.BeginInvoke(cb, state);
}
private static void LongRunningTransaction()
{
Thread.Sleep(5000);
}
}
Part II. Pre-Render Page Async Calls
The first situation where we may want to execute some long-running task asynchronously is when there is work required when the page loads. We can prevent a main thread from IIS being blocked while the work is being performed by using the Page.AddOnPreRenderCompleteAsync() method. This will delegate a thread from the threadpool to handle the long-running request and complete the page response. The request will actually be executed between the PreRender and PreRenderComplete events. This approach can give us a boost in performance from IIS.
I always try to turn off AutoEventWireup in my pages so I don't get a bunch of extra events slowing things down. In the code-behind for the sample page, I'm executing the AddOnPreRenderCompleteAsync() method from the OnInit() of the page. As soon as the OnInit() method has completed firing, the designated begin method will fire. Alternatively, we could explicitly run all the registered async tasks with the Page.ExecuteRegisteredAsyncTasks() method.
We need two delegates to pass to the AddOnPreRenderCompleteAsync, the first one is for beginning the long-running transaction and the second for when it is complete. The begin method has the following signature:
delegate IAsyncResult BeginMethod(Object sender, EventArgs e, AsyncCallback cb, object state);
The result method has the standard result signature:
delegate void ResultMethod(IAsyncResult asyncResult);
Here is one way to wire up the page:
public partial class AddOnPreRenderCompleteAsyncPage : System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
Page.AddOnPreRenderCompleteAsync(BeginDoSomething, EndDoSomething);
}
IAsyncResult BeginDoSomething(Object sender, EventArgs e, AsyncCallback cb, object state)
{
Response.Write("<br> BeginDoSomething Fired at" + DateTime.Now.ToLongTimeString());
return LongRunner.BeginLongRunningTransaction(cb, state);
}
void EndDoSomething(IAsyncResult asyncResult)
{
Response.Write("<br> EndDoSomething Fired at " + DateTime.Now.ToLongTimeString());
}
}
And here is an example of the same wiring using anonymous methods:
public partial class AddOnPreRenderCompleteAsyncPageB : System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
Page.AddOnPreRenderCompleteAsync(
JeanniePosted Aug 23, 2007, 11:52 AM
When calling a referenced business object from a web application (exists in an external project) will making an Async call simply create a new thread from the same thread pool that the web application is already using? Note - this would not be a webservice call or a db call.