Most of the mainstream IoC containers have their own implementation of a custom controller factory for ASP.NET MVC, but Unity doesn’t. There is an implementation in the MvcContrib project, but I don’t like the way it works, so I decided to implement it myself.

Unity Controller Factory

After a few mail exchanges with a guys of the p&p team and with Brad Wilson I came out with the following 35 lines of code.

public class UnityControllerFactory: DefaultControllerFactory
{
    protected override IController GetControllerInstance(Type controllerType)
    {
        IController controller;
        if (controllerType == null)
            throw new HttpException(
                    404, String.Format(
                     "The controller for path '{0}' could not be found" +
			"or it does not implement IController.",
                     this.RequestContext.HttpContext.Request.Path));
        if (!typeof(IController).IsAssignableFrom(controllerType))
            throw new ArgumentException(
                    string.Format(
                        "Type requested is not a controller: {0}",
                        controllerType.Name),
                        "controllerType");
        try
        {
            controller = MvcUnityContainer.Container.Resolve(controllerType)
                            as IController;
        }
        catch (Exception ex)
        {
            throw new InvalidOperationException(String.Format(
                                    "Error resolving controller {0}",
                                    controllerType.Name),ex);
        }
        return controller;
    }
}

public static class MvcUnityContainer
{
    public static UnityContainer Container { get; set; }
}

And the only things needed to use it is creating the container, passing it to the controller factory, registering the dependencies (repositories, services) and finally setting the custom controller factory.

//Create UnityContainer
UnityContainer container = new UnityContainer();

//Configure container
container.RegisterType<IFrontendService, FrontendService>();
container.RegisterType<IDateTimeProvider, DateTimeProvider>();
container.RegisterType<IFrontendDataAccess, SqlFrontendDataAccess>();

//Set container for Controller Factory
MvcUnityContainer.Container = container;

//Set for Controller Factory
ControllerBuilder.Current.SetControllerFactory(
                    typeof(UnityControllerFactory));

Implementation possibilities

There are two possibilities when you want to write a custom controller factory:

  • Implement IControllerFactory and implement the CreateContoller method that returns a controller based on the controller name
  • Inherit from DefaultControllerFactory and override GetControllerInstance which returns a controller based on the type that is needed

The first gives you complete freedom on the naming conventions of your controllers, but has two downsides: first it needs you to register not only the external references but also the controllers (container.RegisterType<IController, HomeController>("Home")). Second you also have to implement the logic to discover the correct controller based on the namespace and, more importantly with MVC v2, with the Areas.

The second approach delegates to the default implementation the mapping of the controller name to the type of the controller. Less freedom with the naming convention, but also less code to write both in the controller factory and also during the setup of your application.

Applying the same concept to Ninject

I think the Ninject controller factory uses the first approach and might not work with Areas in MVC v2, so I think I’ll submit a patch to adopt this easier approach.