In the case of delegating message handlers, each one starts the next one by calling base.SendAsync
and then (asynchronously) waits for it to complete by using await
. So, they can handle both pre- and post- conditions.
The normal code works just as you'd expect:
// At this point, no later handlers (or the controller) have executed.
// All earlier handlers have run up until the point they call base.SendAsync.
var response = await base.SendAsync(request, cancellationToken);
// At this point, all later handlers (and the controller) have executed and completed.
// All earlier handlers are (asynchronously) waiting for you to complete.
It is not possible for C
to complete before B
, because B
is awaiting SendAsync
on C
, so B
will not complete until after C
completes.
Remember that message handlers are bidirectional. They're split up into the "pre" part (before the base.SendAsync
call) and the "post" part (after the await
of the task returned from base.SendAsync
). So, when your handler's SendAsync
is invoked, you know that all the "pre" parts of earlier filters have already run, but none of their "post" parts. Same for the controller: all "pre" parts of all filters have run, but none of the "post" parts.
Now, if you were to do something bad, like not await the task returned from base.SendAsync
, then you won't get the nice behavior above and things get complicated. But the vast majority of the time, your handler code does an await base.SendAsync
, and is split cleanly into "pre" and "post" parts.