How to create asynchronous ASP.NET pages using C#
IIS combined with ASP.NET provides many technologies to improve performance and scalability. IIS provides a pool of threads so that it can server many requests simultaneously. The pool has a limited number of threads in it, and once they are used up additional requests can start to pile up. Keeping the total number of active threads down is an attempt to prevent too many active threads from consuming all of the available CPU time. According to Andy Defrancesco with today’s data intensive websites, much of the time threads are tied up waiting for an external resource such as a request from a web service or from a database. Asynchronous pages in ASP.NET can boost performance in these situations by enabling threads in the pool to be used to serve additional requests while an operation is waiting for an external resource request to complete.
Suppose you have a website with two web pages. One is your home page which display’s a greeting, and the second page displays a large dataset from a database. You have 25 threads in your thread pool. 25 people simultaneously are accessing the database query page, and one additional person comes onto the site to see the home page which has static content on it. And if your website sees high levels of traffic, consider switching to dedicated hosting plans to ensure that your site doesn’t slow down.
Compare these two scenarios:
Synchronous database driven page: While everyone is waiting for the dataset to load, all available threads are in use so the 26th request for the home page becomes blocked.
Asynchronous database driven page: While 25 requests are waiting for data from the database, those threads are returned to the pool for work. When the 26th request comes in for the home page, that page is returned immediately. As the datasets are returned the threads are drawn out of the thread pool to finish serving the pages. The result is that the threads spend much more time available to serve requests.
Here are two good pages for getting started with asynchronous ASP.NET pages:
Asynchronous ASP.NET Page Processing by Peter Bromberg
Use Threads and Build Asynchronous Handlers in Your Server-Side Web Code by Fritz Onion
After reading these and some other articles, here is a piece of code to get you started. I put this together to process a job in the background as a generic pattern. I wrap my big job in a delegate so that I can get an IAsyncResult object back. This simplifies things, because in most examples I read you get this by calling a web service asynchronously but this is’t always what you want done.
Step 1: Make an empty asp.net page. Add async=”true” to the @Page tag in the .aspx file.
Step 2: In the class code, declare a delegate
public delegate void AsyncTaskDelegate();
Step 3: Declare a member variable in the class to prevent the delegate from going out of scope
AsyncTaskDelegate _runnerDelegate = null;
Step 4: Create a method that will be run asynchronously:
public void DoJob()
this.GridView1.DataSource = GetDatasetFromDatabase(); this.GridView1.DataBind();
Step 5: Tell the framework you want your job run. You can put this in Page_Load or in a response to a button click / postback:
// Register async methods
Step 6: Add the event to kick off the delegate and run the job asynchronously.
IAsyncResult OnBegin(object sender, EventArgs e, AsyncCallback cb, object state)
_runnerDelegate = new AsyncTaskDelegate(this.DoJob);
IAsyncResult result = _runnerDelegate.BeginInvoke(cb, state);
Step 7: Add an event handler for after the request finishes
void OnEnd(IAsyncResult ar)
All together, it looks like this:
1: public partial class Async : System.Web.UI.Page
3: public delegate void AsyncTaskDelegate();
5: AsyncTaskDelegate _runnerDelegate = null;
7: IAsyncResult OnBegin(object sender, EventArgs e, AsyncCallback cb, object state)
9: _runnerDelegate = new AsyncTaskDelegate(this.DoJob);
10: IAsyncResult result = _runnerDelegate.BeginInvoke(cb, state);
11: return result;
14: public void DoJob()
16: this.GridView1.DataSource = new AsyncTaskDelegate(this.DoJob);
20: void OnEnd(IAsyncResult ar)
25: protected void Button1_Click(object sender, EventArgs e)
27: // Register async methods
29: new BeginEventHandler(OnBegin),
30: new EndEventHandler(OnEnd)