Dependency Injection in ASP.NET MVC: Filters

So far, we’ve looked at extending the advantages of dependency injection to our controllers and its various services.  We started with a basic controller factory that merely instantiates controllers to one that takes advantage of the modern container feature of nested/child containers to provide contextual, scoped injection of services.  With a child container, we can do things like scope a unit of work to a request, without needing to resort to an IHttpModule (and funky service location issues).

Having the nested container in place gives us a nice entry point for additional services that the base controller class builds up, including filters.  Right after controllers, filters are one of the earliest extension points of ASP.NET MVC that we run into where we want to start injecting dependencies.

However, we quickly run into a bit of a problem.  Out of the box, filters in ASP.NET MVC are instances of attributes.  That means that we have absolutely no hook at all into the creation of our filter classes.  If we have a filter that uses a logger implementation:

public class LogErrorAttribute : FilterAttribute, IExceptionFilter
{
    private readonly ILogger _logger;

    public LogErrorAttribute(ILogger logger)
    {
        _logger = logger;
    }

We’ll quickly find that our code using the attribute won’t compile.  You then begin to see some rather heinous use of poor man’s dependency injection to fill the dependencies.  But we can do better, we can keep our dependencies inverted, without resorting to various flavors of service location or, even worse, poor man’s DI.

Building Up Filters

We’ve already established that we do not have a window into the instantiation of filter attributes.  Unless we come up with an entirely new way of configuring filters for controllers that doesn’t involve attributes, we still need a way to supply dependencies to already-built-up instances.  Luckily for us, modern IoC containers already support this ability.

Instead of constructor injection for our filter attribute instance, we’ll use property injection instead:

public class LogErrorAttribute : FilterAttribute, IExceptionFilter
{
    public ILogger Logger { get; set; }

    public void OnException(ExceptionContext filterContext)
    {
        var controllerName = filterContext.Controller.GetType().Name;
        var message = string.Format("Controller {0} generated an error.", controllerName);

        Logger.LogError(filterContext.Exception, message);
    }
}

The LogErrorAttribute’s dependencies are exposed as properties, instead of through the constructor.  Normally, I don’t like doing this.  Property injection is usually reserved for optional dependencies, backed by the null object pattern.  In our case, we don’t really have many choices.  To get access to the piece in the pipeline that deals with filters, we’ll need to extend some behavior in the default ControllerActionInvoker:

public class InjectingActionInvoker : ControllerActionInvoker
{
    private readonly IContainer _container;

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

    protected override FilterInfo GetFilters(
        ControllerContext controllerContext, 
        ActionDescriptor actionDescriptor)
    {
        var info = base.GetFilters(controllerContext, actionDescriptor);

        info.AuthorizationFilters.ForEach(_container.BuildUp);
        info.ActionFilters.ForEach(_container.BuildUp);
        info.ResultFilters.ForEach(_container.BuildUp);
        info.ExceptionFilters.ForEach(_container.BuildUp);

        return info;
    }
}

In our new injecting action invoker, we’ll first want to take a dependency on an IContainer.  This is the piece we’ll use to build up our filters.  Next, we override the GetFilters method.  We call the base method first, as we don’t want to change how the ControllerActionInvoker locates filters.  Instead, we’ll go through each of the kinds of filters, calling our container’s BuildUp method.

The BuildUp method in StructureMap takes an already-constructed object and performs setter injection to push in configured dependencies into that object.  We still need to manually configure the services to be injected, however.  StructureMap will only use property injection on explicitly configured types, and won’t try just to fill everything it finds.  Our new StructureMap registration code becomes:

For<IActionInvoker>().Use<InjectingActionInvoker>();
For<ITempDataProvider>().Use<SessionStateTempDataProvider>();
For<RouteCollection>().Use(RouteTable.Routes);

SetAllProperties(c =>
{
    c.OfType<IActionInvoker>();
    c.OfType<ITempDataProvider>();
    c.WithAnyTypeFromNamespaceContainingType<LogErrorAttribute>();
});

We made two critical changes here.  First, we now configure the IActionInvoker to use our InjectingActionInvoker.  Next, we configure the SetAllProperties block to include any type in the namespace containing our LogErrorAttribute.  We can then add all of our custom filters to the same namespace, and they will automatically be injected.

Typically, we have a few namespaces that our services are contained, so we don’t have to keep configuring this block too often.  Unfortunately, StructureMap can’t distinguish between regular attribute properties and services, so we have to be explicit in what StructureMap should fill.

The other cool thing about our previous work with controller injection is that we don’t need to modify our controllers to get a new action invoker in place.  Instead, we work with our normal DI framework, and the controller is unaware of how the IActionInvoker gets resolved, or which specific implementation is used.

Additionally, since our nested container is what’s resolved in our InjectedActionInvoker (StructureMap automatically resolves IContainer to itself, including in nested containers), we can use all of our contextual items in our filters.  Although I would have preferred to use constructor injection on my filters, this design is a workable compromise that doesn’t force me to resort to less-than-ideal patterns such as global registries, factories, service location, or poor man’s DI.

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.
  • http://weblogs.asp.net/psteele Patrick Steele

    Cool. I did the same thing Windsor a while ago. It’s nice how open and extensible the MVC framework is:

    http://weblogs.asp.net/psteele/archive/2009/11/04/using-windsor-to-inject-dependencies-into-asp-net-mvc-actionfilters.aspx

  • Darren

    Have you tried MvcTurbine?

  • http://www.lostechies.com/members/jflanagan/default.aspx Joshua Flanagan

    Patrick, its interesting that you see this post as a positive example of ASP.NET MVC. You could do the same BuildUp trick with Pages in ASP.NET WebForms:

    http://stackoverflow.com/questions/869199/mvp-pattern-using-webforms-and-di-object-instantiation/1693870#1693870

    Wouldn’t it be nicer if the framework was built with dependency injection in mind and you didn’t have to resort to this?

  • Erik

    @Josua: But in this case setter injection is only required for a few attributes.

    Note on every single codebhind file.

    @Jimmy
    I am curious what other ways you are using attributes on your MVC deployments.

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

    @Erik

    Pretty much filters and validation attributes. Attributes are fairly limited in their use, and work best for metadata (and less for behavior, as we see here). You can’t use generics, lambdas, expressions, etc etc.

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

    Not sure if you’ve thought of this when doing Filter injection but one cool aspect of pulling filters from your IoC within your custom action filter is the ability to have ‘global filters’.

    For example, your LogErrorAttribute can just be a LogErrorFilter that implements IErrorFilter. From there you can just ask the container for any IErrorFilter impl and add them to your info.ExceptionFilters collections.

    This way if you want to log errors across all your actions (or controllers), you get that simpler than explicitly tagging each controller/action with the attribute.

  • http://channel9.msdn.com sampy

    Oxite *ducks* does what Javier suggests. It has a (way too complicated) filter registry where you can specify rules that are evaluated at filter retrieval time to get the set of filters needed for the action. Filters are then created via the container. In the new Channel9, we still use CAI to apply filters globally but I don’t use the registry yet. If I find I need it, I’ll bring it back but not yet.

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

    Almost forgot! Another thing to watch out for is that the Controller class implements all the filter interfaces and is returned as an element in each of the lists (action, exception, etc.) that are exposed from FilterInfo.

    So if you have any public properties that can be injected (or happen to match by some chance), the BuildUp mechanism will re-inject them into your controller. This could be good or bad, depending on your case.

    In MVCTurbine, I opted to exclude the controller from the filter list since anything that a controller _should_ require needs to be injected via a constructor (IMO).

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

    @Javier, @sampy

    I’m not a big fan of the action filter model for MVC as is. I can’t easily add a filter to all controllers to an area, etc. I feel like I have to build a contrived inheritance hierarchy just for filters. In the future, I’d rather go for a filter registration model.

    I don’t even like that Controller implements all the filters, it’s just bizarre, back to the Page model. I’m just waiting until Jeremy posts a “here’s how we do it in Fubu”.

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

    @jimmy,

    Yeah, you’re right. The way filters are implemented (and applied) is obtuse and it can use some loving. However, I’m not sure a lot of people would understand the benefits from using something that’s disconnected from the action (and attribute) since everything else that’s out there follows this model close.

    And yes, I too am looking for Jeremy’s Fubu series

  • http://blog.rajan.net.in Rajan

    Hi,
    Nice article. I am trying to implement similar to above for Error Logger with HandleErrorAttribute. The new syntax for structure map is the lamda way and for RouteCollection i have implemented like x.ForRequestedType().TheDefault.Is.IsThis(RouteTable.Routes); But still i am getting error StructureMap Exception Code: 202
    No Default Instance defined for PluginFamily System.Web.Routing.RouteBase. Any idea?

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

    @Rajan

    What version of MVC are you using? This example is for MVC 2.

  • http://blog.rajan.net.in Rajan

    Thanks, I am using MVC 1.0

  • http://jeffbarnes.net/blog Jeff Barnes

    Something to keep in mind regarding custom action invokers that recently bit me…

    If you intend to use a custom action invoker from an AsyncController, be sure to inherit from AsyncControllerActionInvoker rather than ControllerActionInvoker. Otherwise, your asychronous methods will get dispatched as standard synchronous methods. For AsyncController, the AsyncControllerActionInvoker ultimately triggers the method name matching that pairs ActionNameAsync with ActionNameCompleted.

    This wasn’t immediately obvious to me and took some time to trace down the root cause.

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

    @Jeff

    Good call, thanks for the heads up!

  • PT

    Late to the game, but for posterity’s sake, why not call BuildUp() from inside the attribute?

    public class CPOPAuthorizeAttribute : AuthorizeAttribute
    {
    private ISecurityService securityService; // will be setter injected

    public ISecurityService SecurityService
    {
    get { return securityService; }
    set { securityService = value; }
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
    if (httpContext == null)
    throw new ArgumentNullException(“httpContext”);

    if (!httpContext.User.Identity.IsAuthenticated)
    return false;

    ObjectFactory.BuildUp(this);

    return false;

    }

    }

    Am I doing something glaring wrong (to everyone but me)? :)

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

    @PT

    No, it’s not wrong. BuildUp is for property injection, which I see as a bit of a compromise. It’s more difficult to configure that way (I have to explicitly tell the container what it needs to pay attention to), and I find it to be less explicit. It’s perfectly acceptable. I try and avoid it at all costs, when it’s just not possible to get my own ctor in there somewhere.

  • Cosmin Onea

    how do you dispose the action filters? Say one of them depends on database connections or other resources. When are you releasing the resources.

  • http://twitter.com/chester89 Gleb Chermennov

    Did something change in ASP.NET MVC? Because I can’t make that code work right now – container has the implementation, but after BuildUp call my property is still null

  • http://twitter.com/chester89 Gleb Chermennov

    My bad – I forgot to include my service namespace into a SetUpAllProperties call. Everything works now. Thanks

  • Jovana

    Very useful post.

    Do you have any idea what can be done in case of injecting dependencies to web api filters?

  • http://samlea.ch/blog/ Sam Leach

    Thanks for this post. Is this still the a recommended way to inject dependencies into action filters?

    • jbogard

      Eh, probably not, I don’t bother with this any more. Too much work, not a clear gain.

      • http://samlea.ch/blog/ Sam Leach

        Thanks for your response. I have a performance issue where we are using a Service Locator to resolve a dependency inside an action filter. The resolution takes too long. If this method is too much work, what is the recommended way to inject a dependency into an action filter today?

        • jbogard

          A performance issue? There should be no performance difference doing injection vs. service location, the mechanism will be the same.