Injecting dependencies into ASP.NET MVC 3 action filters. What's wrong with this approach?
Asked Answered
B

3

82

Here's the setup. Say I have some action filter that needs an instance of a service:

public interface IMyService
{
   void DoSomething();
}

public class MyService : IMyService
{
   public void DoSomething(){}
}

I then have an ActionFilter that needs an instance of that service:

public class MyActionFilter : ActionFilterAttribute
{
   private IMyService _myService; // <--- How do we get this injected

   public override void OnActionExecuting(ActionExecutingContext filterContext)
   {
       _myService.DoSomething();
       base.OnActionExecuting(filterContext);
   }
}

In MVC 1/2 injecting dependencies into action filters was a bit of a pain in the ass. The most common approach was to use a custom action invoker as can be seen here: http://www.jeremyskinner.co.uk/2008/11/08/dependency-injection-with-aspnet-mvc-action-filters/ The main motivation behind this workaround was because this following approach was considered sloppy and tight coupling with the container:

public class MyActionFilter : ActionFilterAttribute
{
   private IMyService _myService;

   public MyActionFilter()
      :this(MyStaticKernel.Get<IMyService>()) //using Ninject, but would apply to any container
   {

   }

   public MyActionFilter(IMyService myService)
   {
      _myService = myService;
   }

   public override void OnActionExecuting(ActionExecutingContext filterContext)
   {
       _myService.DoSomething();
       base.OnActionExecuting(filterContext);
   }
}

Here we're using constructor injection and overloading the constructor to use the container and inject the service. I do agree that does tightly couple the container with the ActionFilter.

My question though is this: Now in ASP.NET MVC 3, where we have an abstraction of the container being used (through the DependencyResolver) are all these hoops still necessary? Allow me to demonstrate:

public class MyActionFilter : ActionFilterAttribute
{
   private IMyService _myService;

   public MyActionFilter()
      :this(DependencyResolver.Current.GetService(typeof(IMyService)) as IMyService)
   {

   }

   public MyActionFilter(IMyService myService)
   {
      _myService = myService;
   }

   public override void OnActionExecuting(ActionExecutingContext filterContext)
   {
       _myService.DoSomething();
       base.OnActionExecuting(filterContext);
   }
}

Now I know that some purists might scoff at this, but seriously, what would be the downside? It's still testable as you can use the constructor that takes an IMyService at test time and inject a mock service that way. You're not tied down to any implementation of DI container since you're using the DependencyResolver, so are there any downsides to this approach?

Incidentally, here's another nice approach for doing this in MVC3 using the new IFilterProvider interface: http://www.thecodinghumanist.com/blog/archives/2011/1/27/structuremap-action-filters-and-dependency-injection-in-asp-net-mvc-3

Benefice answered 25/8, 2011 at 14:54 Comment(4)
Thanks for linking to my post :). I think this would be fine. Despite my blog posts from earlier this year, I'm not actually a big fan of the DI they included in MVC 3 and have't been using it lately. It seems to work but kinda feels awkward at times.Requisite
If you're using Ninject, this could be a possible approach: #6193914Heifetz
+1, although the service locator is considered an anti-pattern by many, I think I prefer your approach over Marks for its simplicity and also the fact that the dependency is resolved in one place, the IOC container, whereas in Mark's example you would have to resolve in two places, in the bootstrapper and when registering the global filters, which feels wrong.Swacked
you can still use the "DependencyResolver.Current.GetService(Type) anytime you want to.Heraclea
I
33

I'm not positive, but I believe you can just use an empty constructor (for the attribute part) and then have a constructor that actually injects the value (for the filter part).*

Edit: After a little reading up, it appears that the accepted way to do this is via property injection:

public class MyActionFilter : ActionFilterAttribute
{
    [Injected]
    public IMyService MyService {get;set;}
    
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        MyService.DoSomething();
        base.OnActionExecuting(filterContext);
    }
}

Regarding the why not use a Service Locator question: It mostly just reduces the flexibility of your dependency injection. For example, what if you were injecting a logging service, and you wanted to automatically give the logging service the name of the class it's being injected into? If you use constructor injection, that would work great. If you're using a Dependency Resolver/Service Locator, you'd be out of luck.

Update

Since this got accepted as the answer, I'd like to go on the record to say that I prefer Mark Seeman's approach because it separates the Action Filter responsibility away from the Attribute. Furthermore, Ninject's MVC3 extension has some very powerful ways to configure action filters via bindings. See the following references for more details:

Update 2

As @usr pointed out in the comments below, ActionFilterAttributes are instantiated when the class is loaded, and they last the entire lifetime of the application. If the IMyService interface is not supposed to be a Singleton, then it ends up being a Captive Dependency. If its implementation isn't thread-safe, you could be in for a lot of pain.

Whenever you have a dependency with a shorter lifespan than your class's expected lifespan, it's wise to inject a factory to produce that dependency on-demand, rather than injecting it directly.

Idyllic answered 25/8, 2011 at 15:7 Comment(11)
Re your comment about the lack of flexibility: Behind the DependencyResolver is an actual IOC container driving it, so you can add any custom logic you want right in there when building up an object. Not sure I follow your point.....Benefice
@BFree: When calling DependencyResolver.GetService, the binding method has no idea what class this dependency is being injected into. What if you wanted to create a different IMyService for certain types of action filters? Or, as I said in my answer, what if you wanted to provide a special argument to the MyService implementation to tell it what class it's been injected into (which is useful for loggers)?Idyllic
OK, I did some messing around, and you're 100% right, there's no way to get the "context" of which the current resolution is happening, so yes that's a downside. Good point. I would argue though, that adding an Inject attribute is ugly as well though, as that ties your service to an implementation of a particular container as well, where as my DependencyResolver approach does not. I'll leave this question open for a bit, I'm just curious to hear more opinions. Thanks!Benefice
@BFree: I agree that property injection is less-than-ideal. Feel free to leave the question open as long as you like. I'm interested in hearing other solutions as well. Regarding the Injected attribute, you can specify your own attribute via the NinjectSettings.InjectAttribute property. This makes it easy to keep your Ninject references contained in your DI setup code.Idyllic
I hate posting comments on old questions, but in regards to the question "What if you wanted to provide a special argument to the implementation (i.e. loggers)", it's been my experience that you can still use the service locator pattern in this manner. Just have the service locator return logger factory. Then you can call LoggerFactory.Create(someParameter) to inject the parameters you need. I believe this is commonly referred to as the abstract factory pattern.Sulla
@Chris: Thanks for the comment. The idea with the "special argument" question was that your special argument could be automatically provided via dependency resolution. The example in the question was a logger, which often takes the class that uses it as a parameter. As you say, you could have every class construct its own logger by calling ServiceLocator.Get<LoggerFactory>().Create(typeof(Foo)), but this opens you up to a high probability of copy-paste errors. If you don't change the type param, The log might say an error message is produced by a Foo when it's actually produced by a Bar.Idyllic
@Strip: A logger case is special in this regard, I think, at least depending on how you do it. For me, each class that needs logging gets an ILoggerFactory injected via DI, and then calls LoggerFactory.Create(this); in its constructor. Because the statement is self-referencing by nature, there aren't any copy/paste errors to speak of.Sulla
Action filters are shared across requests in MVC 3. This is highly thread-unsafe.Rehash
@usr: I appreciate your comment, but I don't think the answer deserved your downvote. This code isn't inherently "highly thread-unsafe." It's only not thread-safe if MyService.DoSomething() isn't thread-safe. It doesn't introduce any new thread-safety issues that weren't already in the OP's code. Nor is it any less thread-safe than Mark Seeman's answer. However, I did update the answer to indicate that action filters are shared across requests, so you need to watch out for Captive Dependencies.Idyllic
OK, I have removed the downvote. It was not appropriate. I'll delete these comments eventually. The MVC3 change to make filters singletons is, in my mind, without positive value and very dangerous. My intention was to save others some trouble when they find out about that in production.Rehash
Beware, by using the [Injected] attribute, you are taking a dependency on your container in your action filter. I'm not familiar with a lot of DI containers, but LightInject, when configured for Web API, will properly inject a service into action filters without having to use any kind of [Injected] attribute.Resort
P
98

Yes, there are downsides, as there are lots of issues with IDependencyResolver itself, and to those you can add the use of a Singleton Service Locator, as well as Bastard Injection.

A better option is to implement the filter as a normal class into which you can inject whichever services you'd like:

public class MyActionFilter : IActionFilter
{
    private readonly IMyService myService;

    public MyActionFilter(IMyService myService)
    {
        this.myService = myService;
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if(this.ApplyBehavior(filterContext))
            this.myService.DoSomething();
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if(this.ApplyBehavior(filterContext))
            this.myService.DoSomething();
    }

    private bool ApplyBehavior(ActionExecutingContext filterContext)
    {
        // Look for a marker attribute in the filterContext or use some other rule
        // to determine whether or not to apply the behavior.
    }

    private bool ApplyBehavior(ActionExecutedContext filterContext)
    {
        // Same as above
    }
}

Notice how the filter examines the filterContext to determine whether or not the behavior should be applied.

This means that you can still use attributes to control whether or not the filter should be applied:

public class MyActionFilterAttribute : Attribute { }

However, now that attribute is completely inert.

The filter can be composed with the required dependency and added to the global filters in global.asax:

GlobalFilters.Filters.Add(new MyActionFilter(new MyService()));

For a more detailed example of this technique, although applied to ASP.NET Web API instead of MVC, see this article: http://blog.ploeh.dk/2014/06/13/passive-attributes

Piggyback answered 25/8, 2011 at 17:13 Comment(15)
Thanks for your answer, but no offense, all your links simply point to philosophical arguments about naming of patterns. After reading through all of your answers to other questions you've linked, and to the blog posts, I still don't see any concrete issues that would arise from using my approach. Add to that that now any ActionFilter I use in my application I need to remember to add to the global filters, and I'd argue that this approach could lead to errors of its own. If you can give a concrete example as to how my approach can lead to errors, then I'll admit I'm being thickheaded :)Benefice
You asked about what the downsides would be: the downsides are decreased maintainability of your code base, but that hardly feels concrete. This is something that creeps up on you. I can't say that if you do what you propose to do, you will have a race condition, or the CPU may overheat, or kittens will die. That's not going to happen, but if you don't follow proper design patterns and avoid anti-patterns, your code will rot and four years from now you'll want to rewrite the application from scratch (but your stakeholders won't let you).Piggyback
Fair enough. I will agree with you, that if I'm building an all purpose ActionFilter that may be used across projects, then yes, this can be an anti-pattern, as the default constructor may be called, and if DependencyResolver isn't used, you'd get some weird errors. However 1)your approach still requires registration with the GlobalFilters which can lead to the same issue I've stated above, and 2)What if this action filter isn't uses across applications? What if this action filter is internal? Still as bad?Benefice
In the long run, code based on static state is just harder to maintain. It's global data and we've known for ~40 years that this is bad. There's no way around it...Piggyback
One more question (I'm not challenging, I'm genuinely curious). How would you implement those methods you commented out? Wouldn't you be duplicating logic that's already in the base ActionFilterAttribute class? Seems like an awful lot of work just to avoid having a default constructor on the class consuming the service...Benefice
+1 for showing how to separate the action filter code from the attribute code. I'd prefer this method solely for the sake of separation of concerns. I do appreciate the OP's frustration with the vagueness on the "what's wrong with this" part of the question though. It's easy to call something an anti-pattern, but when his specific code addresses most of the arguments against the anti-pattern (unit-testability, binding via configuration, etc.), it would be nice to know why this pattern makes code rot faster than "purer" code might. Not that I'm disagreeing with you. I enjoyed your book, BTW.Idyllic
@BFree: By the way, Remo Gloor has done some fantastic stuff with the MVC3 extension for Ninject. github.com/ninject/ninject.web.mvc/wiki/… describes how you can use Ninject bindings to define an action filter that gets applied to controllers or actions with a specific attribute on them, rather than having to register the filters globally. This transfers even more control into your Ninject bindings, which is the whole point of IoC.Idyllic
How to implement the methods - sketch: the ActionDescriptor which is part of the filterContext implements ICustomAttributeProvider, so you can pull the marker attribute from there.Piggyback
@Mark: four years from now you'll want to rewrite the application from scratch (but your stakeholders won't let you) - or they will let him and the product dies because the TTM is too long.Fanniefannin
How does MVC know to apply the filter when you decorate actions with the attribute? Does it just use naming conventions?Obsecrate
@ajbeaven: It doesn't. MVC applies the filter globally. Note the code comments, "Look for a marker attribute in the filterContext or use some other rule to determine whether or not to apply the behavior."Idyllic
This is by far my favorite approach. I love Mark's blogs - they are always spot on. The only drawback to this approach is that the filter gets evaluated on every action, regardless of if it will be applied. If one was to register 100 such global action attributes, where only one actually applied, would there be a noticeable performance hit? That's a lot of reflection calls checking for the existence of an attribute isn't it? Overall, I think the maintainability and not having to use an IoC to achieve DI outweighs any drawback, but it would be interesting to see in an extreme example.Heuristic
@Heuristic How do you think the ASP.NET framework finds and invokes the attributes that it defines? ;)Piggyback
@MarkSeemann I hadn't looked into it yet, but I figured they might do some type of preAction and postAction private calls after the action has been selected. Judging by your response, I'm guessing that they are simply registering them as global filters at run-time? Time to go digging!Heuristic
If you dislike globally adding filters, are performing IOC, and so using DefaultControllerFactory.CreateController, you can do the following (forgive the 1-liner, which I don't suggest): ((Controller)base.CreateController(requestContext, controllerName)).ActionInvoker = _customActionInvoker where _customActionInvoker implements ControllerActionInvoker and you can override and control GetFilters. If you care for example code, I'll post a followup answer to Mark's.Nonrecognition
I
33

I'm not positive, but I believe you can just use an empty constructor (for the attribute part) and then have a constructor that actually injects the value (for the filter part).*

Edit: After a little reading up, it appears that the accepted way to do this is via property injection:

public class MyActionFilter : ActionFilterAttribute
{
    [Injected]
    public IMyService MyService {get;set;}
    
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        MyService.DoSomething();
        base.OnActionExecuting(filterContext);
    }
}

Regarding the why not use a Service Locator question: It mostly just reduces the flexibility of your dependency injection. For example, what if you were injecting a logging service, and you wanted to automatically give the logging service the name of the class it's being injected into? If you use constructor injection, that would work great. If you're using a Dependency Resolver/Service Locator, you'd be out of luck.

Update

Since this got accepted as the answer, I'd like to go on the record to say that I prefer Mark Seeman's approach because it separates the Action Filter responsibility away from the Attribute. Furthermore, Ninject's MVC3 extension has some very powerful ways to configure action filters via bindings. See the following references for more details:

Update 2

As @usr pointed out in the comments below, ActionFilterAttributes are instantiated when the class is loaded, and they last the entire lifetime of the application. If the IMyService interface is not supposed to be a Singleton, then it ends up being a Captive Dependency. If its implementation isn't thread-safe, you could be in for a lot of pain.

Whenever you have a dependency with a shorter lifespan than your class's expected lifespan, it's wise to inject a factory to produce that dependency on-demand, rather than injecting it directly.

Idyllic answered 25/8, 2011 at 15:7 Comment(11)
Re your comment about the lack of flexibility: Behind the DependencyResolver is an actual IOC container driving it, so you can add any custom logic you want right in there when building up an object. Not sure I follow your point.....Benefice
@BFree: When calling DependencyResolver.GetService, the binding method has no idea what class this dependency is being injected into. What if you wanted to create a different IMyService for certain types of action filters? Or, as I said in my answer, what if you wanted to provide a special argument to the MyService implementation to tell it what class it's been injected into (which is useful for loggers)?Idyllic
OK, I did some messing around, and you're 100% right, there's no way to get the "context" of which the current resolution is happening, so yes that's a downside. Good point. I would argue though, that adding an Inject attribute is ugly as well though, as that ties your service to an implementation of a particular container as well, where as my DependencyResolver approach does not. I'll leave this question open for a bit, I'm just curious to hear more opinions. Thanks!Benefice
@BFree: I agree that property injection is less-than-ideal. Feel free to leave the question open as long as you like. I'm interested in hearing other solutions as well. Regarding the Injected attribute, you can specify your own attribute via the NinjectSettings.InjectAttribute property. This makes it easy to keep your Ninject references contained in your DI setup code.Idyllic
I hate posting comments on old questions, but in regards to the question "What if you wanted to provide a special argument to the implementation (i.e. loggers)", it's been my experience that you can still use the service locator pattern in this manner. Just have the service locator return logger factory. Then you can call LoggerFactory.Create(someParameter) to inject the parameters you need. I believe this is commonly referred to as the abstract factory pattern.Sulla
@Chris: Thanks for the comment. The idea with the "special argument" question was that your special argument could be automatically provided via dependency resolution. The example in the question was a logger, which often takes the class that uses it as a parameter. As you say, you could have every class construct its own logger by calling ServiceLocator.Get<LoggerFactory>().Create(typeof(Foo)), but this opens you up to a high probability of copy-paste errors. If you don't change the type param, The log might say an error message is produced by a Foo when it's actually produced by a Bar.Idyllic
@Strip: A logger case is special in this regard, I think, at least depending on how you do it. For me, each class that needs logging gets an ILoggerFactory injected via DI, and then calls LoggerFactory.Create(this); in its constructor. Because the statement is self-referencing by nature, there aren't any copy/paste errors to speak of.Sulla
Action filters are shared across requests in MVC 3. This is highly thread-unsafe.Rehash
@usr: I appreciate your comment, but I don't think the answer deserved your downvote. This code isn't inherently "highly thread-unsafe." It's only not thread-safe if MyService.DoSomething() isn't thread-safe. It doesn't introduce any new thread-safety issues that weren't already in the OP's code. Nor is it any less thread-safe than Mark Seeman's answer. However, I did update the answer to indicate that action filters are shared across requests, so you need to watch out for Captive Dependencies.Idyllic
OK, I have removed the downvote. It was not appropriate. I'll delete these comments eventually. The MVC3 change to make filters singletons is, in my mind, without positive value and very dangerous. My intention was to save others some trouble when they find out about that in production.Rehash
Beware, by using the [Injected] attribute, you are taking a dependency on your container in your action filter. I'm not familiar with a lot of DI containers, but LightInject, when configured for Web API, will properly inject a service into action filters without having to use any kind of [Injected] attribute.Resort
E
8

The solution Mark Seemann suggested seems elegant. However pretty complex for a simple problem. Using the framework by implementing AuthorizeAttribute feels more natural.

My solution was to create a AuthorizeAttribute with a static delegate factory to a service registered in global.asax. It works for any DI container and feels slightly better than a Service Locator.

In global.asax:

MyAuthorizeAttribute.AuthorizeServiceFactory = () => Container.Resolve<IAuthorizeService>();

My custom attribute class:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class MyAuthorizeAttribute : AuthorizeAttribute
{
    public static Func<IAuthorizeService> AuthorizeServiceFactory { get; set; } 

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        return AuthorizeServiceFactory().AuthorizeCore(httpContext);
    }
}
Emmalineemmalyn answered 25/3, 2015 at 10:47 Comment(1)
I like this code because you don't high couple the Service Locator with MyAuthorizeAttribute.Aplacental

© 2022 - 2024 — McMap. All rights reserved.