Ninject Binding Attribute to Filter with Constructor Arguments
asp.net-mvc-3, attributes, dependency-injection, filter, ninject
Solution
I have figured it out (thanks to Remo's directions and documentation).
Use the appropriate .WithConstructorArgument extension whether you are binding to a Controller or Action filter. For example binding my action filter looks like this:
kernel.BindFilter<AuthorizationFilter>(FilterScope.Action, 0)
.WhenActionMethodHas<RequireRolesAttribute>()
.WithConstructorArgumentFromActionAttribute<RequireRolesAttribute>("requiredRoles", o => o.RequiredRoles);
Once I understood the Func<> signature, it all became clear. The best way I found to handle this was to
make the extension type-specific for my attribute
.WithConstructorArgumentFromActionAttribute<TAttribute>()
fetch the value from the callback object (your attribute) via lambda:
("argumentName", o => o.PropertyName)
Problem
I read as many answers as I could for this, but they seem to fall short of one detail. The trouble is when binding an action filter (with a service injected by controller) to a corresponding attribute, I've been unable to figure out how to pass parameter/property values from the attribute to its bound filter. Below is the code, and below that my intended fake-code: Filter & Attribute ``` public class AuthorizationFilter : IAuthorizationFilter { private readonly IAuthorizationService _authorizationService; private readonly UserRoles _requiredRoles; // Enum public AuthorizationFilter(IAuthorizationService authorizationService, UserRoles requiredRoles) { _authorizationService = authorizationService; _requiredRoles = requiredRoles; } public void OnAuthorization(AuthorizationContext filterContext) { if (filterContext.HttpContext.Session == null) HandleUnauthorizedRequest(filterContext); else { var authorized = _authorizationService.IsUserInRole((UserSessionInfoViewModel) filterContext.HttpContext.Session["user"], _requiredRoles); if (!authorized) HandleUnauthorizedRequest(filterContext); // else TODO: deal with cache... } } } public class RequireRolesAttribute : FilterAttribute { public readonly UserRoles RequiredRoles; public RequireRolesAttribute(UserRoles requiredRoles) { RequiredRoles = requiredRoles; } } ``` Filter/Attribute Bindings ``` kernel.BindFilter<AuthorizationFilter>(FilterScope.Controller, 0) .WhenControllerHas<RequireRolesAttribute>(); kernel.BindFilter<AuthorizationFilter>(FilterScope.Action, 0) .WhenActionMethodHas<RequireRolesAttribute>(); ``` This should make sure any controller/action decorated with [RolesRequired] is bound to the filter. So far so good. Now I want to declare via the attribute the roles (much like the stock AuthorizeAttribute) and pass those values onto the filter that actually does the authorization. Intended/Fake Code: ``` [RequireRoles(UserRoles.Author)] public ActionResult Index() { // blah } ``` Specifically, What does it take to inform the AuthorizationFilter of the roles? Can the filter/ninject access the arguments passed to the attribute's constructor? Can the filter/ninject pull them from the attributes public property? For reference, these articles were a huge help, but don't answer this one thing: Dependency Injection with Ninject and Filter attribute for asp.net mvc Custom Authorization MVC 3 and Ninject IoC B Z, Remo Gloor, others... how can I accomplish this?