Another day, another Entity Framework (and ASP.NET MVC 5) async problem, and another solution for you! Actually, today I have two solutions for you! This time, I ran into a problem with HttpContext’s Items collection losing my IoC container when execution resumed after an await. The fix is simple once you understand what’s going on.
[more]
Let’s start by looking at the problem. I always use the container-per-request pattern in my ASP.NET applications. I store a StructureMap child container in my HttpContext’s Items collection at the start of each request:
public class MvcApplication : System.Web.HttpApplication { public IContainer Container { get { return (IContainer) HttpContext.Current.Items["_Container"]; } set { HttpContext.Current.Items["_Container"] = value; } } //Snip! public void Application_BeginRequest() { Container = ObjectFactory.Container.GetNestedContainer(); } public void Application_EndRequest() { Container.Dispose(); Container = null; } }
When wired up through ASP.NET MVC’s dependency resolver, this ensures that everything that’s created while servicing a request is isolated to the current request and disposed of correctly once the request has finished. It’s a pattern that’s served me well for many years. That is, until I started making async calls! When I did that, I started to receive NullReferenceException’s from the dependency resolver when trying to find the container in HttpContext’s Items collection. After a bit of digging, I found this answer on Stackoverflow, and I understood what was going on. My app’s web.config file didn’t specify that the app was targeting .NET 4.5. Because of that, ASP.NET MVC fell back in to "quirks mode" for .NET 4.0, and its SynchronizationContext went into a mode that didn’t work with async/await. Ugh.
There are several ways to fix this issue. I opted for adding aspnet:UseTaskFriendlySynchronizationContext=true to my web.config’s appSettings. This blog post has more information on the various options, quirks mode, and how it might impact you.
But Wait, There’s More!
Another thing to be aware of: even once you get out of quirks mode, you may still run in to issues related to HttpContext. HttpContext.Current is not always available in a worker thread, so, inside of a call that you have awaited, you may (or may not) be able to get at the current context. That’s usually a good thing as you shouldn’t be writing code directly against HttpContext, but I discovered this little land-mine when an injected service that I was using was attempting to grab something from the context’s session. My code would randomly work, and randomly blow up with a nice, cryptic error:
To get around the problem, I started exposing the current HttpContext via the nested container that was bound to my request, like so:
void Application_BeginRequest(object sender, EventArgs e) { Container = ObjectFactory.Container.GetNestedContainer(); Container.Configure(x => { x.For<HttpContextBase>().Use(new HttpContextWrapper(HttpContext.Current)); }); }
I then updated the service to use the HttpContextBase that was registered in the container rather than hitting HttpContex.Current. Problem solved!