The following is the sequence of operations of an asynchronous PreRequestHandler execution.
- Thread A executes the Global constructor (implemented in Global.asax). In the constructor, the AddOnPreRequestHandlerExecuteAsync method is called. Then Thread A executes Application_Start, Application_BeginRequest, etc.
- Thread B executes BeginPreRequestHandlerExecute.
- Thread C executes MyCallback, EndPreRequestHandlerExecute, Page_Load, and Application_EndRequest.
Thread A, Thread B and Thread C might be different depending on how many tasks in the thread pool.
There is a gap between Thread B and Thread C because there must be some thread(s) to queue the Web service calls, make the calls, receive the responses, and even launch a thread pool thread to execute MyCallback. At the first glance, one might argue that there is no thread gain because there always is (are) thread(s) sitting somewhere to do the tasks mentioned above even though Thread A and Thread B are freed. It is important to understand that the Web services “interface” is the XML message on the wire, not the class definition one may work with to process in VB or C#. Basically there is a dedicated group of threads that is responsible to queue the Web service calls, send and receive all SOAP messages. The following diagram illustrates that.
All the requests share the same group of threads. So we do have thread gain! This is the key why this approach is efficient.