Keeping Asp.NET MVC Controller Constructors Clean In a Dependency Injection World

Update: After playing around with the concepts I talked about in this post I now pretty much disagree with what I wrote here. To see why, see part 2.


In my experience, dependency injection has proven to be invaluable when creating applications. It has allowed me to easily follow test driven development practices, be confident that my application functions as expected, and it gives me confidence that any bugs I had previously found do not crop up again.

However, one trend that I have noticed is that as my Asp.NET MVC application becomes more complex, my controller constructors are becoming bloated with all of the service objects that the controller might use. I say might because not all the service objects are being used in all actions, but they must be passed into the controller’s constructor to facilitate unit testing. This issue of constructor bloat is made worse due to my business/service layer being made up of many small query and command classes. Here is an example of one of my controllers:


public class ContactController : MyAppBaseController
{
    public ContactController( ContactsByCompanyQuery contactsByCompanyQuery,
                                        ContactByIdQuery contactByIdQuery,
                                        CreateContactCommand createContactCommand,
                                        EditContactCommand editContactCommand,
                                        ISearchProvider searchProvider,
                                        IEmailProvider emailProvider)
    { 
        // copy parameters into variables
    }
}

As you can see from this example, as I add more actions to my controller and need more service classes I have to add more parameters into my controller, which also means I have to update all unit tests to use this new parameter when instantiating the controller. This also strikes me as inefficient as it requires the inversion of control system to always instantiate all service classes even when the executing MVC action may only need one or two.

I needed a system that would allow me to minimize the number of parameters in my controller constructors while still giving me full flexibility with dependency injection and retaining the ability to unit test my controllers and mock my service classes. After thinking about this problem for a bit I came up with the idea of creating a factory class that instantiates service classes on demand directly from the IoC system. As I use Castle Windsor for IoC I created the following factory class:

    public class WindsorServiceFactory : IServiceFactory
    {
        protected IWindsorContainer _container;

        public WindsorServiceFactory(IWindsorContainer windsorContainer)
        {
            _container = windsorContainer;
        }

        public ServiceType GetService<ServiceType>() where ServiceType : class
        {
            // Use windsor to resolve the service class.  If the dependency can't be resolved throw an exception
            try { return _container.Resolve<ServiceType>(); }
            catch (ComponentNotFoundException) { throw new ServiceNotFoundException(typeof(ServiceType)); }
        }
    }

It turned out to be a much simpler solution than I thought it would be. Now my constructors look like

public class ContactController : MyAppBaseController
{
    protected IServiceFactory _serviceFactory;

    public ContactController (IServiceFactory factory)
    {
        _serviceFactory = factory;
    }

    public ActionResult Search(string query)
    {
        var results = _serviceFactory.GetService<ISearchProvider>().Search(query);
        return View(results);
    }
}

This is much cleaner in my opinion and it also allows me to completely ignore my constructors even as I add more functionality into my controllers.

I am also able to easily use this in my unit tests with mocks. Here is an example using Moq:

[TestMethod]
public void Can_Search_Contacts()
{
    // Setup
    var factory = new Mock<IServiceFactory>();
    var searchProvider = new Mock<ISearchProvider>();
    factory.Setup( x => x.GetService<ISearchProvider>()).Returns(searchProvider.Object);
    var controller = new ContactController(factory.Object);
    
    // Act
    var result = controller.Search();

    // Add verifications here
}

Advertisements

9 responses to “Keeping Asp.NET MVC Controller Constructors Clean In a Dependency Injection World

  1. Hey,

    I really don’t think this is what you want to be doing. when you perform a unit test, you now need to know which services are called within the code you are testing – leaking implementation details.

    Sure, it makes your constructors nice and skinny, but that’s probably a sign you need to fix something else. Look at some recent posts by Rob Ashton on Code better.

    • I’m not sure I see what you mean. The information you have to know (what services you have to setup for unit testing) is exactly the same as you would need to pass in to the constructors. Either way you still know what services the classes implement by what you either pass into the controllers, or what is going to be requested by the IServiceFactory class.

  2. I think that you need to give a fuller description of what’s happening inside your controller actions so we can see how the commands are being used. I was assuming that you could write your action methods to take the command/query model type which would be supplied via custom model binding. How those commands/queries use your services would be up to you (it depends what the commands actually do). For instance you could get the search query model and pass it the service in the action method (query.From(_searchService) or the query could be provided with its service dependency via IoC in the custom model binder. Here’s a post about model binding and IoC. http://iridescence.no/post/Constructor-Injection-for-ASPNET-MVC-Model-Binders.aspx

    • In my application’s architecture commands and queries aren’t traditional models, they don’t hold any information really. Instead they are lightweight classes that perform an action. So for example when I want to create a user my code looks like:

      new CreateUserCommand(_unitOfWork).Execute(new CreateUserCommandParams
      {
      UserName = actionModel.Username,
      PlainTextPassword = actionModel.Password,
      Email = actionModel.Email
      });

      This class looks at the parameters supplied, performs any validation required, runs any supported queries (for example a query class that looks for a user with a specific email address, to prevent duplicate emails), and then calls the data layer to create the user in the database. They are short lived classes, but they tend to depend on one or more other query classes (for example, security checks are separate query classes).

      Your link kind of makes sense on how I would instantiate these classes in the action parameters, though I will have to do some thinking on if it makes sense (although this is admittedly partly due to my inexperience with MVC model binders, as I haven’t done anything with them yet), but it could be a lot of overhead, rather than just using property injection as Ayende suggests. I’ll have to think it over.

      Thanks for the reply 🙂

  3. My personal belief is that everything vitally needed for the object to operate, should be injected through its class constructor. This gives you a clear, at-a-glance representation of class responsibilities and dependencies.
    When you notice, that a class constructor has too many arguments (i.e. dependencies), this might mean that it’s overloaded with responsibilities and a candidate for refactoring.

    • I have come to agree, and the method I presented here in this article has proven to be a real pain for reasons I didn’t think about at the time. I’ve been meaning to write a follow-up but I’ve been distracted.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s