views:

679

answers:

2

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.

+3  A: 

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! :-)

mookid8000
I agree: attributes shouldn't be "executable" but just a tag.
Mauricio Scheffer
thanks a lot for your answer! I got running with a few mods: 1) the Container.Resolve line is requiring a generic parameter. I changed it to use Container.Resolve(serviceType) and cast it. 2) I inherited mvccontrib WindsorControllerFactory and added the ActionInvoker in CreateController().
Christian Dalager
+3  A: 

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

Patrick Steele