How do I use Windsor to inject dependencies into ActionFilterAttributes
Asked Answered
B

2

17

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.

Ballerina answered 16/2, 2009 at 13:39 Comment(0)
F
11

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

Flush answered 16/2, 2009 at 14:6 Comment(2)
I agree: attributes shouldn't be "executable" but just a tag.Hartsfield
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().Ballerina
A
18

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

Amr answered 6/11, 2009 at 12:41 Comment(2)
I preferred the method at that link as well.Jon
Nice post thank you! I've got it working very quickly and the usage is much nicer than the generic MyFilterAttribute optionMontherlant
F
11

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

Flush answered 16/2, 2009 at 14:6 Comment(2)
I agree: attributes shouldn't be "executable" but just a tag.Hartsfield
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().Ballerina

© 2022 - 2024 — McMap. All rights reserved.