Filter constructor injection using Ninject
Asked Answered
N

3

11

I am trying to find a way to use Ninject to inject constructor dependencies into filters. I am finding many articles describing property injection which is now advised against, but the remainder of articles involve complex setups with factories, locators, global wrappers or stub attributes.

With MVC allowing you to override almost any part of it's operation I would have thought it would be simply a case of creating your own filter provider in a similar fashion to how you create your own dependency resolver.

What is the now correct way to allow injection, or does it become easier if you use certain types of filters vs others?

 public class UserValidationAttribute : ActionFilterAttribute
 {
    private IRepository repository;

    public UserValidationAttribute(IRepository repository)
    {
        this.repository = repository;
    }
}
Nudity answered 25/9, 2013 at 20:24 Comment(2)
Just a note - The general consensus seems to be that property injection should be used for optional dependencies, but constructor injection for required dependencies (which kind of makes sense - you can't construct a type without its required dependencies, but properties may not get injected based on which services are available to the container)Boccie
I've now implemented the method where you have a global filter which checks if it applies by looking at whether a token attribute is present. What I don't get at the moment is that when I use the token attribute on the action and use filterContext.ActionDescriptor.IsDefined(typeof(MyTokenAttribute), true) I get true, but if I only put the token attribute on the controller I get false.Nudity
C
2

Assuming that the attribute is to be a part of the metadata, which means that it should be instantiated at the compile time, it is not possible to have a repository injected into an attribute by any ioc container. Containers operate in run time.

Christology answered 25/9, 2013 at 21:38 Comment(0)
E
18

There is a way to use constructor injection.

First you replace your attribute with an 'empty' one which you will just use as a marker

public class UserValidationAttribute : Attribute { }

Then you create a filter class as an IActionFilter.

public class UserValidationFilter : IActionFilter
{
    private readonly IRepository repository;

    public UserValidationFilter(IRepository repository)
    {
        this.repository = repository;
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        //do something
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        //do something
    }      
}

Then you can register it with something like

private static void RegisterServices(IKernel kernel)
{
    kernel.BindFilter<UserValidationFilter>(FilterScope.Action, 0)
        .WhenActionMethodHas<UserValidationAttribute>();
}

If your attribute itself has constructor parameters, you can pass them in like

kernel.BindFilter<UserValidationFilter>(FilterScope.Action, 0)
    .WhenActionMethodHas<UserValidationAttribute>();
    .WithConstructorArgumentFromActionAttribute<UserValidationAttribute>("myParameter", attr => attr.MyParameter);

The BindFilter syntax is part of Ninject.Web.Mvc.FilterBindingSyntax.

Effete answered 26/9, 2013 at 11:55 Comment(0)
C
2

Assuming that the attribute is to be a part of the metadata, which means that it should be instantiated at the compile time, it is not possible to have a repository injected into an attribute by any ioc container. Containers operate in run time.

Christology answered 25/9, 2013 at 21:38 Comment(0)
F
0

If you want to inject dependencies to a filer, you want to use property injection instead of constructor injection.

public class UserValidationAttribute : ActionFilterAttribute
{
    [Inject]
    private IRepository repository { get; set; }

    public UserValidationAttribute()
    {
    }
}

https://mcmap.net/q/257712/-injecting-dependencies-into-asp-net-mvc-3-action-filters-what-39-s-wrong-with-this-approach

Fiji answered 25/9, 2013 at 21:45 Comment(1)
his dependency is a repository which seems to be required, so it should be injected via constructor. Also, I feel that sprinkling your IoC magical attributes in your classes is a bad pattern. Most IoC containers today support injecting into MVC filters, including Ninject, Unity v3, and StructureMapToile

© 2022 - 2024 — McMap. All rights reserved.