Thursday 9 November 2006

Tech Ed - Asynchronous ASP.NET Programming

Went to a lecture by Jeff Prosise about Asynchronous ASP.NET Programming which was really interesting. The first thing to note is that this subject is really under documented considering its such an important architecture to use as it can allow you to scale your site.

He explained that when IIS receives an ASP.NET requests it is passed to the worker process, which then allocates it a worker thread from its managed pool of available threads. This thread will remain with the request for its entire lifetime. The worker process also manages an IO thread pool for allocating to any processes that require to carry out any IO.

As there is a finite number of worker process threads that can serve requests it is possible for a busy site to become saturated with requests that cannot be served and clients will start to receive 503 errors. If this occurs we need to scale out the site so serve more requests. One way of doing this is buying more hardware, but the better option is to write our code to utilise the thread by writing asynchronous code. If our code is asynchronous the worker thread can return to the pool to serve more requests whilst we wait for any long running actions such as IO or db actions to occur.

He showed us a couple of ways to make our ASP.NET pages asynchronous, they both involved setting the Async attribute to true in our page directive and then either do the following:
Call AddOnPreRenderCompleteAsync in the page load to register our two Begin and End delegates which can then be used in the page to do the long running process.
or
Create a PageAsyncTask delegate that contains our two Begin and End delegates and register this with the RegisterAsyncTask. This method has the advantage of being able to maintain the thread context, create many tasks, and have a timeout value.

The Async delegates will be called just after the preRender event.

We can use ADO.NET BeginExecuteReader to return the IAsyncResult object to pass up to the return of BeginAsyncOperation method. We also have to complete the EndAsyncResult.

I think if we do make all of our IO methos asynchronous we could really improve the scaleability of our sites – I certainly we be pushing to get some of these changes included in the next releases of my sites :)

He then spoke about creating http handlers which are just classes that adhere to the IHttpHandler object. You can register these with specific file types (not that useful) or create a ashx file with a webhandler directive and ASP.NET will automatically use this object when it is requested by the client. Using this instead of a classic aspx file is great for requests that will not be returning form/asp.net type data such as images as it does not have all the overhead of the pipeline that a aspx request moves through.

He showed us a demo of using a ashx object to return pictures by having a normal img tag on a page that had its src set to navigate to the ashx file with a set of params. When the page renders it calls off to the ashx file which returns the graphic without having to go through the same pipeline that a aspx page would have had to. This results is a much quicker response for the client.

He explained that by default an http handler is synchronous but we can make them asynchronous by conforming to IHttpAsyncHandler instead. You just have to have an empty ProcessRequest method and then fill in the BeginProcessRequest and EndProcessRequest with the work. This is then called asynchronously by ASP.NET.

He showed a good demo of a site pulling back images from virtual earth which render much quicker when using asynchronous calls.

He noted that more improvements could be made by editing the max no of concurrent connections in machine.config.

He also told us to Avoid thread.start Threadpool.queueuserworkitem and Asynchronous delegates and that we should use custom thread pools if necessary as otherwise you can steal a thread from the same pool as the ASP.NET worker process.

No comments: