Dependency Injection in ASP.NET MVC: Controllers

After working for 5 years with WebForms, it was quite a breath of fresh air to deal with simple controllers and actions with MVC.  Even better was that there is support for IoC containers built in to the framework.

However, support for dependency injection does not run very deep in an explicit manner, and some work is required to get your container to take as much control as possible over locating instances of objects.

Dependency injection is one of the most powerful tools in any advanced developer’s toolkit.  The ability to remove the responsibility of instantiating, locating and controlling lifecycle of dependencies both promotes good OO design and opens entirely new avenues of architecture that weren’t feasible before.

But to get started, DI needs to start at the topmost layer of your application, ideally the entry point through which everything else flows.  Unfortunately for us using ASP.NET MVC, there are several entry points, several of which are exposed, several of which are not.

Luckily for us, it’s still possible to ensure that we try and banish the “new” operator for instantiating services as much as possible.  Once we do, those new doors open up to a potentially much more powerful design.

First things first, we need to tackle our first entry point: controllers

The built-in controller factory

ASP.NET MVC uses a specific interface to control lifecycle of a controller, IControllerFactory:

public interface IControllerFactory {
    IController CreateController(
        RequestContext requestContext, 
        string controllerName);
    void ReleaseController(IController controller);
}

One interesting piece to note here is that this interface includes both the instantiation and releasing of the controller instance.  We’ll dive into some interesting applications of this in a future post, but we’ll just leave it alone for now.  The built-in controller factory is the DefaultControllerFactory class, which provides some simple out-of-the-box behavior for instantiation:

return (IController)Activator.CreateInstance(controllerType);

and releasing:

public virtual void ReleaseController(IController controller) {
    IDisposable disposable = controller as IDisposable;
    if (disposable != null) {
        disposable.Dispose();
    }
}

There’s some other behavior in there, as it provides a virtual member to retrieve a controller by type instead of by name (which is just a string).  Since the DefaultControllerFactory provides this string –> System.Type work for us, we’ll just use it.  But instead of the familiar Activator.CreateInstance call, we’ll use our container.

Service-located controllers

Service location is bad…just about 99% of the time.  But service location has to happen somewhere, and it’s ideally at the entry point of our application.  We’ll need to use service location for our controller factory, but that doesn’t mean we can’t still have some control over what gets used.

First, we’ll create our own custom controller factory, and inherit from DefaultControllerFactory.  One minor addition is that we’ll still supply the container use to our controller factory (using StructureMap in this example):

public class StructureMapControllerFactory : DefaultControllerFactory
{
    private readonly IContainer _container;

    public StructureMapControllerFactory(IContainer container)
    {
        _container = container;
    }

Once we have our container, we can now use it to override the GetControllerInstance method:

protected override IController GetControllerInstance(
    RequestContext requestContext, Type controllerType)
{
    if (controllerType == null)
        return null;

    return (IController)_container.GetInstance(controllerType);
}

We’ll leave the ReleaseController method alone (for now).  Finally, we just need to configure our controller factory in the global.asax implementation in Application_Start:

var controllerFactory = new StructureMapControllerFactory(ObjectFactory.Container);

ControllerBuilder.Current.SetControllerFactory(controllerFactory);

You’ll just need to make sure you configure your container before instantiating the controller factory.  So why pass in the container?  I can’t stand service location, as it’s a big roadblock to a lot of other interesting techniques.  Because I pass in the container to the controller factory, I now remove the responsibility of the controller factory of figuring out where to get the container.

So why not use something like Common Service Locator instead of using a container-specific interface?  Isn’t that coupling myself to a specific library?  What about depending on abstractions?

Common Service Locator is pretty much useless.  It’s very limiting in its interface, and only supports the least common denominator among the different containers out there.  Additionally, we’ll be using some of the more powerful features in modern containers soon, and just having the simple “GetInstance<T>” method won’t be enough for what we’re looking for.

In the next post, we’ll integrating some more advanced usages of injection with our controllers, to gain control over the myriad of helper objects used throughout the controller lifecycle.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in ASP.NET MVC, Dependency Injection. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Henning Anderssen

    We had the same discussion recently on my current project, whether to use a common service locator / abstract away the IOC or to use the full power of an IOC.

    We originally abstracted away Structuremap because of testing. At that time we only knew of ObjectFacotory.GetInstance and didnt know of the IContainer interface. Now that we know of the IContainer interface, the testability portion of abstracting away the IOC goes away.
    Another argument for abstracting away the IOC is the possibility for changing the IOC later in the project. “Makes it easier to swap out the IOC” and all that stuff. However, the likelyhood that you will EVER change the IOC is extremely small, especially when using Structuremap. And if you decide to swap out the IOC, you’re likely to make changes in your code anyway.

    We use the same method for creating our instances, and it works like a charm. There is only a few places where we have to resort to service location.

  • http://lozanotek.com/blog Javier Lozano

    I think what you meant to say was “Common Service Locator is pretty much useless for our needs” :)

    In all reality, yes, using your IoC to its fullest, is the definitely the way to go since you can build the app to best use different features the container provides.

    The big issue that some teams suffer is that they tend to get too hung up on the intersection between their IoC and the application rather than just embracing it and developing the app.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Javier

    I’ve tried to use it in several of our projects (OSS or otherwise), and the answer has been (so far) a different design, or different configuration option like exposing Func etc. No one seems to even be developing on it either.

  • http://www.tavaresstudios.com Chris Tavares

    CommonServiceLocator was intended for use by libraries that needed / wanted DI services, but did not want to force their choice of container on their consumers. It was never intended to be used in applications. I agree, there’s pretty much zero reason to switch containers. And heck, if you did it right, changing the container wouldn’t actually touch that much code.

  • http://www.wwwlicious.com Mac

    I found the same thing with the common service locator. It’s a great idea in principle but it’s too restrictive in trying to utilise the flexibility of an IoC like structuremap. The inability to occasionally inject/override parameters pretty much killed it for me.

    Agree with Henning about the testing with the IContainer, we switched to that approach and so far it works very well.

  • http://www.lucisferre.net Chris Nicola

    Sharp Architecture has this feature out of the box using Windsor. I definitely recommend MVC and IoC newbs check it out.

  • http://sm-art.biz ulu

    Rather than returning a null, I return base.GetControllerInstance(). This way, I get a more meaningful exception when I mistype the controller name.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @ulu

    Good call! Yeah, I just ran into this the other day and was wondering the right way to go. The base class provides a nice implementation.

  • http://blog.buzzuti.com RyanAnderson

    JB – If you encapsulate DI into its own library, you can wrap up your DI container and loosen the dependency on a specific DI container.

    Something like this in your App_Start,
    ControllerBuilder.Current.SetControllerFactory(new MyIsolatedDiContainerLib.StructureMapControllerFactory());
    (excuse the poor naming conv…)
    This way the reference to StructureMap could be eliminated.

    That way, if another DI flavor comes that you like better, you merely need to swap it out in you isolated DI Lib.
    Like what you guys do in CodeCamp Server, with the StructureMapControllerFactory in the isolated DI Lib.

  • http://blog.buzzuti.com RyanAnderson

    JB – Disregard…. Just read Henning Anderssen post, and I concur… Likelyhood of DI con swap is nil… And IContainer is valuable… Gotta Love JM!

  • Guest

    testing