0

我们使用自定义AuthorizeAttribute来处理用户授权的几个方面。我需要添加对数据库的访问权限以在授权期间检查值。该项目使用 Repository 模式,并且 Repos 都通过 StructureMap 在控制器构造函数中实例化。

不幸的是,似乎没有办法将构造函数注入与过滤器一起使用。我找到了 Jimmy Bogard 的一篇文章(http://lostechies.com/jimmybogard/2010/05/03/dependency-injection-in-asp-net-mvc-filters/),解释了如何使用属性注入来处理这种情况。基本上,Jimmy 的代码会拦截其中的GetFilters方法ControllerActionInvokerBuildUp在每个过滤器上运行以填充属性。这正是我所需要的,所以我添加了以下课程 -

public class InjectingActionInvoker : ControllerActionInvoker
{
    private readonly IContainer _container;

    public InjectingActionInvoker(IContainer container)
    {
        _container = container;
    }

    protected override FilterInfo GetFilters(
        ControllerContext controllerContext, 
        ActionDescriptor actionDescriptor)
    {
        var info = base.GetFilters(controllerContext, actionDescriptor);

        info.AuthorizationFilters.ForEach(_container.BuildUp);
        info.ActionFilters.ForEach(_container.BuildUp);
        info.ResultFilters.ForEach(_container.BuildUp);
        info.ExceptionFilters.ForEach(_container.BuildUp);

        return info;
    }
}

然后用这些线将它连接到 StructureMap -

For<IActionInvoker>().Use<InjectingActionInvoker>();
For<ITempDataProvider>().Use<SessionStateTempDataProvider>();

Policies.SetAllProperties(c =>
{
    c.OfType<IActionInvoker>();
    c.OfType<ITempDataProvider>();
    c.WithAnyTypeFromNamespaceContainingType<UserProfileRepository>();
});

最后,我将公共属性添加到我的自定义AuthorizeAttribute类中 -

[SetterProperty]
public UserProfileRepository User { get; set; }

当我运行项目并访问安全页面时,AuthorizeCore代码被命中两次。第一次,我的财产已设置并正常工作。但是,第二次调用失败,因为属性为 null。我在方法中设置了一个断点GetFilters,它只是第一次被击中。不幸的是,我只是对 StructureMap 或 Filters 的理解不够深入,无法确切地知道它的横向发展。

以下是调用堆栈,以防对任何人有用 -

呼叫#1

AppName.dll!AppName.Filters.SiteAuthorizeAttribute.AuthorizeCore(System.Web.HttpContextBase httpContext) Line 78    C#
[External Code] 
AppName.dll!AppName.Filters.SiteAuthorizeAttribute.OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext) Line 31   C#
[External Code]

呼叫#2

AppName.dll!AppName.Filters.SiteAuthorizeAttribute.AuthorizeCore(System.Web.HttpContextBase httpContext) Line 69    C#
[External Code] 
AppName.dll!AppName.Filters.SiteAuthorizeAttribute.OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext) Line 31   C#
[External Code] 
App_Web_1fnmflat.dll!ASP._Page_Views_Shared__Menu_cshtml.Execute() Line 2   C#
[External Code] 
App_Web_1fnmflat.dll!ASP._Page_Views_Shared__Layout_cshtml.Execute() Line 51    C#
[External Code] 

任何 StructureMap 大师愿意分享一些智慧吗?提前感谢您的帮助!

编辑:这是_Menu.cshtml文件的代码 -

@(Html.Kendo().Menu()
      .Name("Menu")
      .Items(items =>
      {
          items.Add().Text("My Dashboard").Action("Dashboard", "Home");
          items.Add().Text("My Account").Action("Edit", "Account");
          items.Add().Text("Purchase/Renew").Action("Index", "Purchase");
          items.Add().Text("Administration")
              .Items(children =>
              {
                  children.Add().Text("Accounts").Action("Index", "UserProfile");
                  children.Add().Text("Coupons").Action("Index", "Coupon");
              });
          items.Add().Text("Logout").Action("Logout", "Logon");
      })
      )

感谢 NightOwl888 的一些提示,我已将问题隔离到 Kendo Menu 调用。如果我在最后一行设置断点_Menu.cshtml并进入,我会看到为我的 HomeController 调用了 DoGetInstance。一旦完成,第二次触发 OnAuthorization 并且我的 repo 属性为空。

有人知道我在这里缺少什么吗?

4

4 回答 4

0

我也面临同样的问题并尝试不同的方法,最后这在删除后对我有用[AllowMultiple = true],现在AuthorizeCore被调用一次。我很好奇这与AuthorizeCore.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CompanyAuthorizeAttribute : AuthorizeAttribute
{}

之前

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class CompanyAuthorizeAttribute : AuthorizeAttribute
{}
于 2014-12-18T17:07:45.473 回答
0

由于您知道在第二次调用期间没有调用 GetFilters 并且 AuthorizeAttribute 的第一个实例正在工作,因此这显然不是您的 DI 设置的问题。如果正在缓存 AuthorizeAttribute 实例,那么所有依赖项也将被缓存,所以也不是。

问题归结为您的菜单FilterProviders.Providers.GetFilters(controllerContext, actionDescriptor);在使用 AuthorizeAttribute 之前没有调用该方法。我只能猜测为什么,因为您没有提供菜单或其部分方法的代码。

您可以尝试覆盖ControllerActionInvoker.InvokeAuthorizationFilters

于 2014-12-09T08:30:36.137 回答
0

可悲的是,我无法追踪正在发生的事情。所以这就是我现在如何“解决”这个问题 -

    [SetterProperty]
    public UserProfileRepository User
    {
        get { return _user ?? DependencyResolver.Current.GetService<UserProfileRepository>(); }
        set { _user = value; }
    }

当注入工作时,使用注入的值,否则我使用DependencyResolver手动做脏活。不漂亮,但我现在没有其他选择。

于 2014-12-22T20:40:41.783 回答
0

我没有让它与自定义过滤器提供程序一起使用,如该线程中所述:

如何在 ASP.NET Web Api 中对动作过滤器进行单元测试?

我尝试了很多选项,但最终将依赖解析函数注入到我的属性中。这样,单元测试可以注入一个返回假的、模拟的或其他的函数,而应用程序可以注入一个使用 IoC 容器解决依赖关系的函数。

我写了一篇关于我如何让它工作的简短博客文章。很想听听你的想法,如果它对你有帮助:

http://danielsaidi.com/blog/2015/09/11/asp-net-and-webapi-attributes-with-structuremap

于 2015-09-10T10:28:17.097 回答