Introducing Action Injection with Autofac ASP.NET MVC Integration

by Alex Meyer-Gleaves 16 May 2010 - 7:33 PM

There are currently two main approaches to performing dependency injection, Constructor Injection and Setter Injection. The more popular of the two approaches is Constructor Injection. The dependencies that a type has are made obvious because they must be supplied in order to construct an instance. This also makes it easier for you to ensure that a newly instantiated object is in a valid state. When working with a type the constructor is usually the first thing that you come into contact with.

With Setter Injection, also known as Property Injection, it is much more difficult to tell what the dependencies are when looking at the type from the outside. Setter Injection is most useful when you have no control over the instantiation of the type that requires the dependencies to be injected. This is a common scenario for ASP.NET WebForms where the activation of a Page instance is performed by the runtime. You do not have an opportunity to take over the activation process, and the first chance you have to perform dependency injection is when you are provided with an existing instance of Page. In this case you have no choice but to inject the dependencies into the type via its properties.

ASP.NET MVC has many extensibility points and is very flexible. It provides you with the opportunity to take over the creation of your Controller instances by creating your own factory that implements IControllerFactory, or more commonly by deriving from the DefaultControllerFactory and overriding the GetControllerInstance method. This makes it possible for your controllers to take advantage of Constructor Injection, and is exactly what the Autofac ASP.NET MVC Integration does. When it comes to unit testing your controller classes, it becomes very easy to see what dependencies it has, and to provide mock implementations for those dependencies.

An issue that is often raised in regards to Constructor Injection is what some people like to call Constructor Bloat. This may indicate that you are not following the Single Responsibility Principle and that some refactoring may be in order. The number of constructor parameters that would be considered too many would no doubt vary depending on who you ask. In the case of ASP.NET MVC controllers the number of constructor dependencies is more likely to be higher than for other classes. The level of responsibility for a controller is usual greater than what you would expect for an ordinary internal component. This is the result of mapping an external view of the application (URL based) onto an internal representation (controller based).

It turns out that both Nicholas Blumhardt and I found ourselves shifting some of these dependencies out of the controller’s constructor and into the action methods that actually require them. We were both fairly surprised to find out that the other had independently been doing exactly the same thing, and at this point discussed if there was something wrong with the approach because it seemed that no one else was doing it. Surely all good ideas have already been done so this one must be bad. I personally feel that having dependencies injected into your action method should not feel like a foreign concept because that is exactly what MVC is already doing for you with your existing parameters.

For lack of any official term that I am aware of, Action Injection is what I am calling this particular approach to dependency injection in ASP.NET MVC. The more I play around with this approach the more I like it. Your constructor is provided the dependencies that are shared by all actions in your controller, and each individual action can request any additional dependencies that it needs. Now when writing unit tests for your actions there is no need to provide mock implementations for dependencies that your action will not be interacting with. The end result is less mocks in your unit tests and a clear indication of the action’s actual dependencies.

Nick and I have decided to test out the idea of Action Injection in the Autofac ASP.NET MVC Integration. The changes are only in the source code at the moment and have not yet been included in a release. I mentioned earlier that MVC is very extensible and the process for invoking your action methods is no different. It is possible to replace the default behaviour by creating your own IActionInvoker. The easiest way to do this is by deriving from the AsyncControllerActionInvoker class and overriding the appropriate methods. A controller can be requested to use your custom action invoker by assigning an instance to the controller's ActionInvoker property. The current source includes a registration extension that allows you to register an IActionInvoker instance that will be assigned to a controller as it is activated. There is a default IActionInvoker implementation called ExtensibleActionInvoker that allows dependencies to be injected into your action methods. It can also do Setter Injection on your filters but that is a topic for another post. As the name suggests, you can extend this class and add any additional behaviour that you require. Registering controllers in the HttpApplication start would look something like this.

ContainerBuilder builder = new ContainerBuilder();

builder.RegisterType<ExtensibleActionInvoker>()
    .As<IActionInvoker>()
    .WithParameter("injectActionMethodParameters", true);
builder.RegisterControllers(Assembly.GetExecutingAssembly())
    .InjectActionInvoker();

// Register other services.

IContainer container = builder.Build();
_containerProvider = new ContainerProvider(container);

ControllerBuilder.Current.SetControllerFactory(new AutofacControllerFactory(_containerProvider));

I will not go into further detail on the implementation at this point because it may be tweaked a little before being released. Instead, let us look at an example of how we could make our action dependencies clearer using Action Injection. The NotifyController class below has action methods that send the current user a message using different delivery methods.

public class NotifyController
{
    public NotifyController(ILogger logger, 
        IEmailNotifier emailNotifier, 
        ISmsNotifier smsNotifier, 
        IMessengerNotifier messengerNotifier)
    {
        // Implementation.
    }
    
    public ActionResult Email(string message)
    {
        // Implementation.
    }
    
    public ActionResult Sms(string message)
    {
        // Implementation.
    }

    public ActionResult Messenger(string message)
    {
        // Implementation.
    }
}

There are three action methods on this controller and four dependencies that must be provided through the constructor. To unit test any of the action methods all four of the dependencies will need to be mocked. In this controller the ILogger instance is required by all action methods, but the remaining notifier dependencies are each required only by one action method. The controller could be refactored so that it takes the one ILogger dependency through its constructor, and each action could take its particular notifier dependency through a method parameter. Here is an example of how the refactored code would look.

public class NotifyController
{
    public NotifyController(ILogger logger)
    {
        // Implementation.
    }
    
    public ActionResult Email(string message, IEmailNotifier emailNotifier)
    {
        // Implementation.
    }
    
    public ActionResult Sms(string message, ISmsNotifier smsNotifier)
    {
        // Implementation.
    }

    public ActionResult Messenger(string message, IMessengerNotifier messengerNotifier)
    {
        // Implementation.
    }
}

Now when testing the action methods we only ever need to provide two mock services. There is no need to provide additional mock services that will never be used. Assuming we only had one unit test per action and setup our mocks inside each unit test, we would have halved the number of mocks required, taking the total from twelve down to six. That certainly seems like an improvement to me.

I would be interested to know what you think about this idea. Is it totally crazy or could there be something to it? Maybe you too have already been doing this and could share how it has been working out for you.

Tags: ,

Autofac | Web Development

Comments (6) -

Steven Burman
Steven Burman
17 May 2010 - 4:17 AM #

I like the explicitness of the dependencies and think that this is a nice approach overall. There are a couple of considerations that I would like your thoughts on.

1. In terms of testing, this essentially replicates what can be achieved with a combination of constructor injection and property injection, where mocks are only provided for the required optional dependencies.

2. There is likely to be an argument that says that your controller should be refactored to prevent the dependency split that you require in examples like shown above. (I don't neccesarily agree with this but would like to hear your response to the argument.)

Just playing devil's advocate.

Reply

Alex Meyer-Gleaves
Alex Meyer-Gleaves
17 May 2010 - 9:10 AM #

Thanks for the prompt feedback Steven.

1. It is certainly possible to use the combination of constructor injection and property injection to limit the dependencies required for unit testing, but you do not get the same level of discoverability for the action level dependencies. The dependencies that are required at the controller and individual action level are more obvious with constructor injection coupled with action injection. The MVC Integration will continue to support all three forms of dependency injection so you can choose the pattern that works for you. I think that providing another option for dependency injection will give users more flexibility when it comes to building their MVC applications.

2. The example I provided was so simplistic that refactoring into a single dependency that accepted the type of notification or something similar would of course be possible, but the example was only meant to demonstrate the action injection concept. Obviously it was not meant to represent a scenario that could only be addressed using action injection, though in reality I think it is inevitable that as your controller grows you will end up with action methods that have a unique dependency.

The default routing in MVC guides you in a certain direction in regards to the mapping of actions to a controller. Except for very special cases I would tend to stick with this easy to understand routing model. That means that your URL design is going to have an impact on the responsibility that is given to your controller. You could adjust your routing to limit the responsibility of your controllers by directing certain actions to different controller instances, but that would surely only make your application harder to understand.

Also, thanks for playing devil’s advocate! Smile

Reply

Nicholas Blumhardt
Nicholas Blumhardt
18 May 2010 - 2:29 AM #

Another unit testing consideration - once you embrace this technique, you are pushed further towards a kind of pseudo-command pattern:

pubic ActionResult AddItem(string itemName, AddItemCommand command)
{
   command.Execute(itemName);
   return View();
}

This takes all of the meat out of your controllers, making unit testing there a bit less important. (I don't test front-end controllers!? Heresy! Smile)

Reply

Alex Meyer-Gleaves
Alex Meyer-Gleaves
18 May 2010 - 5:00 AM #

Yee-ha! Your spurs are in the mail Nick. Smile

Seriously though, I like how that encapsulates all of the action level dependencies, and as a pattern is very easy to understand.

Reply

Jon Smith
Jon Smith United Kingdom
7 June 2012 - 6:13 PM #

Hi Alex,

I found this excellent blog post while researching how to architect a four-layer enterprise system with MVC3 as the preferred UI layer. Your post rang a bell as my service layer interfaces were getting quite complex, which meant the service layer constructor in the controller had some items in it even though they were the minor case. Your MVC3 Action Method injection works well and has simplified my design.

As well as de-cluttering the constructor needed in the controller there is a second benefit of allowing each service a separate class. This helps as I am planning to edit Steve Sanderson's excellent MVCScaffolding to generate the required action,view, service and DTOs from a template. Having each service as a separate class makes this simpler.

I did want to add one note for others. Your code is out of date, as is the Autofac documentation, on how to enable the IActionInvoker. I found a post by Nicholas Blumhardt that said that you now need .WithParameter("injectActionMethodParameters", true) on the end of the command that registers the IActionInjector. The full code is therefore:

builder.RegisterType<ExtensibleActionInvoker>()
    .As<IActionInvoker>()
    .WithParameter("injectActionMethodParameters", true);

I hope that helps others, and thanks again for an excellent post.

PS. Have you seen the post by Philip Mateescu comparing various .NET DI's for speed. Autofac is very fast. See http://philipm.at/2011/0808/

Reply

Alex Meyer-Gleaves
Alex Meyer-Gleaves Australia
14 June 2012 - 1:02 AM #

Hi Jon,

Thanks for taking the time to point out the missing parameter. I have updated the post to include it. Can you point me to the Autofac documentation that is out-of-date? I don't remember documenting the action injection feature on the wiki but wherever it is I would like to fix it up.

Cheers,

Alex.

Reply

Pingbacks and trackbacks (1)+

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading

About the author

Alex Meyer-Gleaves I'm a Technical Architect living in Australia (that island like continent in the southern hemisphere). I love Microsoft .NET and C#. I hate early mornings, slow drivers and Lotus Notes.

Twitter

Google Shared

 

Month List

Recent Comments

Comment RSS

Links

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010