17
votes

Having seen how NInject can do it and AutoFac can do it I'm trying to figure out how to inject dependencies into MVC ActionFilters using Castle Windsor

At the moment I'm using an ugly static IoC helper class to resolve dependencies from the constructor code like this:

public class MyFilterAttribute : ActionFilterAttribute
{    
  private readonly IUserRepository _userRepository;
  public MyFilterAttribute() : this(IoC.Resolve<IUserRepository>()) { }
  public MyFilterAttribute(IUserRepository userRepository)
  {
     _userRepository = userRepository;
  }
}

I'd love to remove that static antipattern IoC thing from my filters.

Any hints to as how I would go about doing that with Castle Windsor?

And no, changing DI framework is not an option.

2

2 Answers

11
votes

Make a generic attribute: MyFilterAttribute with ctor taking a Type as argument - i.e. something like this:

public class MyFilterAttribute : ActionFilterAttribute {
    public MyFilterAttribute(Type serviceType) {
        this.serviceType = serviceType;
    }

    public override void OnActionExecuting(FilterExecutingContext c) {
        Container.Resolve<IFilterService>(serviceType).OnActionExecuting(c);
        // alternatively swap c with some context defined by you
    }

    // (...) action executed implemented analogously

    public Type ServiceType { get { return serviceType; } }
    public IWindsorContainer Container { set; get; }
}

Then use the same approach as the two articles you are referring to, in order to take control of how actions are invoked, and do a manual injection of your WindsorContainer into the attribute.

Usage: [MyFilter(typeof(IMyFilterService))]

Your actual filter will then be in a class implementing IMyFilterService which in turn should implement IFilterService which could look something like this:

public interface IFilterService {
    void ActionExecuting(ActionExecutingContext c);
    void ActionExecuted(ActionExecutedContext c);
}

This way your filter will not even be tied to ASP.NET MVC, and your attribute is merely a piece of metadata - the way it is actually supposed to be! :-)

18
votes

When I needed this, I built upon the work others have done with Ninject and Windsor to get property injection dependencies on my ActionFilters.