使用构造函数参数过滤的Ninject绑定属性

时间:2011-11-29 03:29:04

标签: asp.net-mvc-3 dependency-injection attributes filter ninject

我为此尽可能多地阅读了答案,但它们似乎没有达到一个细节。

问题在于将动作过滤器(由控制器注入的服务)绑定到相应的属性时,我一直无法弄清楚如何将参数/属性值从属性传递到其绑定过滤器。下面是代码,下面是我想要的伪代码:

过滤器&属性

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;
    }        
}

过滤器/属性绑定

kernel.BindFilter<AuthorizationFilter>(FilterScope.Controller, 0)
      .WhenControllerHas<RequireRolesAttribute>();
kernel.BindFilter<AuthorizationFilter>(FilterScope.Action, 0)
      .WhenActionMethodHas<RequireRolesAttribute>();

这应该确保用[RolesRequired]修饰的任何控制器/动作都绑定到过滤器。到现在为止还挺好。现在我想通过属性声明角色(很像股票AuthorizeAttribute)并将这些值传递给实际执行授权的过滤器。

预期/假冒代码:

[RequireRoles(UserRoles.Author)]
public ActionResult Index()
{
    // blah
}

具体地,

告知AuthorizationFilter角色需要什么? filter / ninject可以访问传递给属性构造函数的参数吗? filter / ninject可以从属性public属性中提取它们吗?

作为参考,这些文章是一个巨大的帮助,但不回答这一点:

Dependency Injection with Ninject and Filter attribute for asp.net mvc

Custom Authorization MVC 3 and Ninject IoC

B Z,Remo Gloor,其他......我怎么能做到这一点?

2 个答案:

答案 0 :(得分:20)

我已经弄明白了(感谢Remo的指示和文档)。

使用相应的 .WithConstructorArgument 扩展名,无论您是绑定到Controller还是Action过滤器。例如,绑定我的动作过滤器如下所示:

kernel.BindFilter<AuthorizationFilter>(FilterScope.Action, 0)
      .WhenActionMethodHas<RequireRolesAttribute>()
      .WithConstructorArgumentFromActionAttribute<RequireRolesAttribute>("requiredRoles", o => o.RequiredRoles);

一旦我理解了 Func&lt;&gt; 签名,一切都变得清晰了。我发现处理这个问题的最好方法是

  1. 为我的属性

    制作特定于扩展名的类型
    .WithConstructorArgumentFromActionAttribute<TAttribute>()
    
  2. 通过lambda:

    从回调对象(您的属性)中获取值
    ("argumentName", o => o.PropertyName)
    

答案 1 :(得分:9)

并将BindFilter扩展方法纳入范围,不要忘记添加;

using Ninject.Web.Mvc.FilterBindingSyntax;