On a quest for the silver bullet..

ASP.NET MVC: DefaultControllerFactory is not thread safe!

I am not sure if this is a bug or a “feature” of the ASP.NET MVC framework. Either way, this is something you should be aware of as it can cause some very hard to track concurrency issues which might leak information between your HttpRequests.

In my last project we used the ASP.NET MVC framework along with StructureMap, which made us create our own controller factory. I just blogged about it here.

If it was a good design decision or not I am not completely certain anymore, but we added some more framework logic to the controller factory, including checking state on the HttpRequest-object. This, it turned out, was a path to trouble. After a while we had unexpected behavior in our system, sometimes it leaked information between HttpRequests it seemed! But since this only happened during stress testing, it was hard to find the cause.

What we found was that the RequestContext.HttpContext-object was not all the way thread safe. When a request hits our custom controller, and the request goes to sleep to serve another request, the HttpContext of the factory changes to the second requests HttpContext. This means that the first request will work on the second requests HttpContext when it wakes up. This is bad news if you are dependent on the HttpContext in your custom controller factory.

The lesson is this: you have to do at least one of the two actions below if you want to access the HttpContext in your custom controller factory.

1)

The problem occurs when you set your controller factory like this (normally in the global.asax file)

1
ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());

If you send in an instance lik this, it will be the only instance of your controller factory, and this is where the HttpContext-concurrency issues arrive in the first place. What you can do, which will take away all the concurrency issues is to send in the type instead of an instance, like this:

1
ControllerBuilder.Current.SetControllerFactory(typeof(CustomControllerFactory));

The drawback to sending in the type is a) your controller factory will be instantiated for every request and b) you cannot send in anything to your instance (since you’re not instantiating it). This might not be a problem, and if not, you’re good to go.

2)

If you have to use one instance only of your controller factory, and you need to access the HttpContext for a request, you MUST use the HttpContext.Current-instance and not the RequestContext.HttpContext. The HttpContext.Current is as far as I’ve tested thread safe.

Not thread safe:

1
RequestContext.HttpContext

The thread safe alternative:

1
HttpContext.Current

I just found out that this is a bug

- Tore Vestues

July 3rd, 2009 at 11:05 (420)


Leave a Reply