In this section, I’ll show you how to eliminate performance problems and the devouring of thread-pool resources with asynchronous approaches to Web service calls that uses Microsoft ASP.NET.
1. Responsiveness of ASP.NET applications
A typical communication scenario is shown below.
A Web browser sends a request to a Web server. To generate a page, the ASP.NET worker process might need to get data from a remote database through a Web service call. Four components might sit on different machines and the calls made might be lengthy network calls.
As we noted earlier, the user experience we focused on Windows Forms applications was to allow the applications to do other things while making the Web service calls. Web Forms applications utilize the request-response model. So the users get used to not expect to do other things (with the application they run) while making a request. However a user will not be happy to see that a page takes 10 seconds to load in cases where heavy loads on the Web site happen while it normally takes 2 seconds to load. So the user experience we focus on Web Forms applications is to provide the (almost) same user experience in cases where heavy loads on the Web site happen, as experience that users normally have.
ASP.NET uses the process-wide CLR thread pool to service requests. The default size of the CLR thread pool is 25 in Framework 1.0 and 20 in Framework 1.1, with separate limits for I/O threads and worker threads. In cases where threads from the thread pool are used to perform work that is not CPU-intensive (like making a request to a remote database or invoking a remote Web Service), it is possible to saturate the thread pool without high CPU utilization. In this scenario, the thread pool is in fact the bottleneck.
There are two approaches to use the thread pool threads efficiently while making Web service calls:
- Asynchronous PreRequestHandler Execution
- Asynchronous Pages
The asynchronous PreRequestHandler execution approach was first introduced by Matt Powell in [3]. The asynchronous pages approach is a combination of [13], [11], [12], and [3]. It utilizes the techniques about asynchronous HttpHandler discussed by Jason Clark and Fritz Onion in [13], [11], and [12], the techniques about asynchronous pages described by Fritz Onion in [11] and [12], the techniques about storing and passing the request-specific state along with the proxy utilized by Matt Powell in [3].
Both approaches allow freeing up the thread pool thread that serves the original request to service additional requests. This is the key for the performance gain! For this reason, we have to make asynchronous Web service calls with the notification (callback) approach.
Two approaches differ on the start and the end points in the HTTP pipeline and also how many pages the approach serves. I’ll discuss the start and the end points in the HTTP pipeline next.