I was working on a presentation and thought the following should fail since the ActionResult isn\'t being returned on the right context. I\'ve load tested it with VS and got no
ASP.NET doesn't have the 'UI thread' need that many clients apps do (due to the UI framework below it). That context isn't about thread affinity, but for tracking the page progress (and other things, like carrying around the security context for the request)
Stephen Toub mentions this in an MSDN article:
Windows Forms isn't the only environment that provides a SynchronizationContext-derived class. ASP.NET also provides one, AspNetSynchronizationContext, though it's not public and is not meant for external consumption. Rather, it is used under the covers by ASP.NET to facilitate the asynchronous pages functionality in ASP.NET 2.0 (for more information, see msdn.microsoft.com/msdnmag/issues/05/10/WickedCode). This implementation allows ASP.NET to prevent page processing completion until all outstanding asynchronous invocations have been completed.
A little more detail about the synchronization context is given in Stephen Cleary's article from last year.
Figure 4 in particular shows that it doesn't have the 'specific thread' behavior of WinForms/WPF, but the whole thing is a great read.
If multiple operations complete at once for the same application, AspNetSynchronizationContext will ensure that they execute one at a time. They may execute on any thread, but that thread will have the identity and culture of the original page.
In your code, HttpContext
is a member of your AsyncController
base class. It is not the current context for the executing thread.
Also, in your case, HttpContext
is still valid, since the request has not yet completed.
I'm unable to test this at the moment, but I would expect it to fail if you used System.Web.HttpContext.Current
instead of HttpContext
.
P.S. Security is always propagated, regardless of ConfigureAwait
- this makes sense if you think about it. I'm not sure about culture, but I wouldn't be surprised if it was always propagated too.
It appears because the Controller captures the Context whereas using System.Web.HttpContext
is live access to what is part of the synchronization context.
If we look at the ASP.NET MVC5 sources we can see that the ControllerBase
class that all controllers inherit from has its own ControllerContext
which is built from the RequestContext
.
I would assume this means that while the synchronization context is lost after a ConfigureAwait(false);
the state of the Controller
in which the continuation is happening still has access to the state of the control from before the continuation via the closure.
Outside of the Controller
we don't have access to this ControllerContext
so we have to use the live System.Web.HttpContext
which has all the caveats with ConfigureAwait(false);
.