March 25, 2010

Dependency Injection and the Controller Factory in ASP.NET MVC

This is a re-post from the older blog. I’m retiring that blog address and this is one of those posts that I refer to when setting up a new project.

Using an IoC is one of those things that can take a time or two to understand where it fits in and how it’s useful. Once you cross the energy barrier, it’s a color in your palette you can’t imagine missing.

Imagine having a QuestionController that takes an interface called DomainRepository. The job of any concrete implementation of the DomainRepository will be to fetch various domain entities from a backing store.

public class QuestionController : Controller
{

  private DomainRepository _repository;

  public QuestionController(
	DomainRepository repository)
  {
    _repository = repository;
  }

  public ActionResult Index()
  {
    ViewData.Model = _repository.AllQuestions;
    return View();
  }

}

This is a perfect place to use an IoC container to provide build a concrete implementation and all of it's dependencies

The gotcha is that ASP.NET MVC, by default, requires its controllers to have default constructors. Luckily, ASP.NET MVC uses a ControllerBuilder to instantiate the controllers using a ControllerFactory. This is an extension point where we can provider our own factory, one that uses the IoC of choice to resolve the controller.

You'll need a class for the new controller factory. This is a minimal implementation that doesn't make use of the MVC 2 requestContext parameter

public class StructureMapControllerFactory : DefaultControllerFactory
{
  protected override IController GetControllerInstance(
	RequestContext requestContext, 
        Type controllerType)
  {
    return 
	ObjectFactory
	.GetInstance(controllerType) as IController;
  }

}

In your bootstrapper, or in the Global.asax.cs, make the ControllerBuilder use the new controller factory

ControllerBuilder.Current
	.SetControllerFactory(
          new StructureMapControllerFactory());

Also, in the bootstrapper, or in the Global.asax, setup your container. This is using StructureMap's 2.6.1 syntax

ObjectFactory.Initialize(factory =>
{
  factory
    .For<DomainRepository>()
    .Use<NoSqlDomainRepository>();
});

These are the minimal steps required to get the ASP.NET MVC web application ready for use with an IoC (e.g., StructureMap).

March 16, 2010

Declarative Style is My Golden Hammer

I was working on a little pet project recently, and I really was tickled when I wrote my unit tests like this:

  public class Given_a_HomeController
  {

    private static HomeController controller;

    [TestClass]
    public class when_asked_for_the_index
    {

      private ActionResult the_result;

      [TestInitialize]
      public void because()
      {
        using_a_new_home_controller();
        after_performing_the_index_action();
      }
      
      public void using_a_new_home_controller()
      {
        controller = new HomeController();
      }

      public void after_performing_the_index_action()
      {
        the_result = controller.Index();
        Assert.IsNotNull(the_result);
      }

      [TestMethod]
      public void it_should_return_a_ViewResult_for_the_Index_view()
      {
        the_result.is_a_ViewResult().for_a_view_named("Index");
      }

    }

If you can read through the test attribute decorators and the public void C# noise, the setup and the tests read like this:

Given a HomeController:
    When asked for the index:
        because:
            using a new HomeController
            after executing the Index action

        it should return a ViewResult for the Index View

It made me smile.