I'm using Windsor as my IoC container for an ASP.NET MVC application. To get dependency injection in my controllers, I'm using a slightly modified WindsorControllerFactory from Andre Loker's post earlier this year. It works great and allows me to easily test my controllers.
I've got some custom ActionFilters that would benefit from dependency injection. Unfortunately, ActionFilters are attributes on controllers and methods and their instantiation is controlled by the framework. There is no extension point to allow custom creation of the ActionFilters. So I can't do constructor dependency injection. However, I can do the next best thing – property dependency injection!
Custom Method Invoker
The ASP.NET MVC framework has an extensibility point when it comes to actually invoking actions on controllers. The default ControllerActionInvoker does everything we need. We need to modify it's behavior just a little bit to allow us to inject property dependencies.
There's a method on ControllerActionInvoker that is used whenever an action with filters is going to be executed. It's appropriately named "InvokeActionMethodWithFilters". This method is passed a collection of ActionFilters that have already been created by the framework (see, this is why we can't use constructor injection). Thanks to Simone Chiaretta for blogging about his custom Ninject-based ActionInvoker, I was able to convert his to a Windsor-based invoker with relative ease:
As you can see, it's pretty straightforward. All we do is loop through all of the ActionFilters and inject any dependant properties. Those of you familiar with Windsor will realize that the IKernel doesn't have an "InjectProperties" method. I grabbed that from Jeremy Skinner's post about using AutoFac to inject properties into ActionFilters. He created an extension method that uses reflection to resolve property dependencies:
Now that we have the plumbing, let's hook it up!
Changes to WindsorControllerFactory
My current implementation of WindsorControllerFactor.GetControllerInstance looks like this:
I just need to add a few lines of code to add my custom WindsorActionInvoker (which is registered inside Windsor!):
Using Property Injection with ActionFilters
So now lets look at how this can be used to add common data to every page. The oft-used example of populating a list of sponsors just happened to be the exact scenario I was facing when I researched this solution. With the WindsorActionInvoker in place, I can now create an ActionFilter to load my sponsor information into ViewData:
Now any method (or an entire controller class) can have this attribute applied and the sponsor information will be loaded before the action is called. Here's an example:
The list of sponsors is available in your view pages and user controls by simply looking at the ViewData dictionary:
A nice solution, but the use of magic string constants ("sponsors") along with where the data are stored (ViewData) didn't sit well. To fix that, I added a few extension methods to abstract out the access to the list of sponsors:
The SetSponsors extension method allows me to change my LoadSponsorsAttribute to be simply:
The GetSponsors extension method on ViewUserControl allows the Sponsors.ascx that I used to display the list to simply call the GetSponsors() method – no access to ViewData or casting required: