OdeToCode IC Logo

MVC 2 Areas and Containers

Tuesday, October 20, 2009

Some projects use a container like StructureMap to completely replace MVC’s DefaultControllerFactory. They do by registering all controllers by name using StructureMap’s scanning feature during application startup.

ObjectFactory.Initialize(x =>
    x.Scan(s => {
                 .NameBy(type =>
                     type.Name.Replace("Controller", ""));

A simple controller factory to make this work would look like this:

public class SimpleControllerFactory : 
    public IController CreateController(
        RequestContext requestContext, string controllerName)

    // ...

As I mentioned in a previous post, using Areas in MVC 2 means you have the potential for multiple controllers with the same name. A Home controller in the parent project, and a Home controller in each sub-project, for example. Now the simple approach we are using in the code above breaks down. We could do some work to make sure we are registering and looking up types using the proper namespaces, but the logic to look at the namespace constraints is already embedded in MVC’s DefaultControllerFactory.

An easier approach is to use the DefaultControllerFactory to lookup controller types and only use StructureMap to instantiate the controller and resolve dependencies. Doing so means we don’t need to scan any assemblies. StructureMap (and most IoC frameworks) are capable of instantiating an unregistered type as long as the type is concrete. All we need to do is derive from DefaultControllerFactory and override the GetControllerInstance method.

public class BetterControllerFactory
    : DefaultControllerFactory 
    protected override IController GetControllerInstance(
        RequestContext requestContext, Type controllerType)
        IController result = null;
        if (controllerType != null)
            result = ObjectFactory.GetInstance(controllerType)
                as IController;
        return result;                

Moral of the story: Don’t automatically throw away the DefaultControllerFactory. You may find it has some conventions you can make use of!