To what extent are HttpApplication async events (eg those registered using AddOnEndRequestAsync
and friends) asynchronous? Does IIS wait for all asynchronous events fired for a particular event to complete before moving onto the next event, or are they 'fire and forget'?
相关问题
- Carriage Return (ASCII chr 13) is missing from tex
- How to store image outside of the website's ro
- 'System.Threading.ThreadAbortException' in
- Request.PathInfo issues and XSS attacks
- How to dynamically load partial view Via jquery aj
It's not clear to me the exact workings when running in integrated pipeline mode, but I can tell you what I see for the non-integrated case, and the semantics should remain the same.
The short answer is that each event handler is fired in series, whether synchronous or asynchronous, and the next is not fired until the previous completes.
You can trace this through the source code.
A request comes in and is stored in a queue. Typically, when the
HttpRuntime
dequeues a request, it initializes anHttpApplication
for the request by calling itsInitInternal
method, passing theHttpContext
as an argument.HttpApplication.InitInternal
initializes a newHttpApplication.ApplicationStepManager
class for the non-integrated-mode case. You can then see it calls theBuildSteps
method on it. This creates anArrayList
to store the steps and constructs and stores all of the steps. Specifically, these steps are implementations of anIExecuteStep
interface. Ultimately, when all of the steps are added, the list is finalized by copying it to an array and saving it for later in a member var_execSteps
.There are several sources for the steps, but the most used you'll see is the
HttpApplication.CreateEventExecutionSteps
which takes the event type (begin request, authorize, etc.) and the steps array to add its steps for that event in. If you drill intoCreateEventExecutionSteps
you can see it adding anIExecuteStep
for each async and sync handler it knows about, from theAsyncEvents
andEvents
tables, respectively. TheIExecuteStep
interface itself basically consists of anExecute
method and aCompletedSynchronously
flag.Now, pause and look back at one of those Add methods like the one you mentioned,
AddOnEndRequestAsync
, and you can see it add info about the async handler to theAsyncEvents
table.CreateEventExecutionSteps
will then walk through this table and anAsyncEventExecutionStep
will be constructed for each handler added.Back to the request flow. After the
HttpRuntime
initializes theHttpApplication
for the request, it calls itsBeginProcessRequest
method, which firesResumeSteps
.ResumeSteps
is the important one where you can see how the steps are used and what the wait strategy is in the async case. You can see it maintaining a_currentStepIndex
into the array of execution steps. Eventually you see it grab the next step from the array and call itsExecute
method. If the step reports that its executionCompletedSynchronously
, it loops and goes again. If not, it lets the method complete and enters into the async abyss.To see what happens in this async case, you have to look at that
AsyncEventExecutionStep
implementation which was created for the async handlers. In itsExecute
implementation, you see it fire the begin handler and pass in a completion callback. In the constructor, you see this callback initialized to a method that eventually calls...HttpApplication.ResumeSteps
again!And so it keeps going, executing steps, sync or async, until the array is overrun at which point it "finishes" the request processing.
The point is, you can clearly see that steps, which translate to the event handlers you add, are executed one by one, and whether sync or async, the following steps are not executed until the current step completes. Your question was whether events are handled one-by-one in this way, but as you can see, in fact it's even more granular, with each event handler being handled this way, so each gets synchronized access to the HttpContext and can operate without worrying about whether they are still "in the right phase" of the pipeline.
Obviously there's other details in that source code, yada yada, but this is the gist.