Tuesday, 28 September 2010

Injecting HttpContextBase into an MVC Controller

It is a shame that when the ASP.NET MVC framework was released they did not think to build IoC support into the infrastructure. All the major components of the MVC engine appear to magically inherit instances of HttpContext and it’s related objects – which can cause no end of problems if you are trying to utilise Unit Testing and IoC. Reading around various articles on the subject just to get around this one problem requires the implementation of several different concepts and you are still left with a work around. The code below, along with the other links referenced in this article is my stab at resolving the issue. There’s probably nothing new here, but it does attempt to relate all the information needed to do this for Castle Windsor. The overview is that all controllers will need to inherit from a base controller, which takes an instance of HttpContext into it’s constructor. It then overrides the property HttpContext in the main controller class, supplying it’s own version instead.

Note: I’m still not sure if providing a default constructor that takes the base instance of HttpContext is a good idea as I’ve not had chance to fully test that functionality – it’s there as a concept that it could be done but from what I’ve learnt recently in injecting HttpContext into Action Filter Attributes I think it will cause problems. Use that constructor with caution!

public abstract class BaseController : Controller
{
public new HttpContextBase HttpContext { get; private set; }

protected BaseController()
{
this.HttpContext = base.HttpContext;
}

protected BaseController(HttpContextBase httpContext)
{
if(httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
HttpContext = httpContext;
}
}

This partial class can then be inherited and used as shown below. Using this ControllerFactory the injection of the HttpContextBase instance will be handled by the IoC container.

public partial class RealWorldController : BaseController
{
public ReadWorldController(HttpContextBase httpContext)
: base(httpContext)
{
...
}
...
}

Now along with Mocking HttpContextBase your controllers should be easy to inject and unit test!

No comments:

Post a Comment