【问题标题】:Dependency Injection with Ninject and Filter attribute for asp.net mvcasp.net mvc 的 Ninject 和 Filter 属性的依赖注入
【发布时间】:2021-11-15 04:14:23
【问题描述】:

我正在为 asp.net mvc 3 编写一个自定义授权过滤器。我需要将一个用户服务注入到类中,但我不知道该怎么做。

public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
    private IUserService userService;
    private string[] roles;

    public AuthorizeAttribute(params string[] roles)
    {
        this.roles = roles;
    }

    public void OnAuthorization(AuthorizationContext filterContext)
    {
        throw new NotImplementedException();
    }
}

我正在使用 ninject 进行依赖注入。我不想使用工厂或服务定位器模式。

我的绑定在 global.acsx 中如下所示:

    internal class SiteModule : NinjectModule
    {
        public override void Load()
        {
            Bind<IUserService>().To<UserService>();
        }
    }

【问题讨论】:

  • 您确定不想使用工厂吗?在这种情况下,您必须在 Application 类中保留对内核的引用,并在控制器构造函数中手动 Get()。在 Mvc 3 工厂中真的很有意义,因为您要覆盖原始工厂。也有 ninject nugets。
  • Jakubmal,那你能用工厂来回答吗?

标签: asp.net-mvc asp.net-mvc-3 ninject


【解决方案1】:

看到这个答案:Custom Authorization MVC 3 and Ninject IoC

如果你想使用构造函数注入,那么你需要创建一个属性和一个过滤器。

/// Marker attribute
public class MyAuthorizeAttribute : FilterAttribute { }

/// Filter
public class MyAuthorizeFilter : IAuthorizationFilter
{
      private readonly IUserService _userService;
      public MyAuthorizeFilter(IUserService userService)
      {
          _userService = userService;
      }

      public void OnAuthorization(AuthorizationContext filterContext)
      {
          var validUser = _userService.CheckIsValid();

          if (!validUser)
          {
              filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary { { "action", "AccessDenied" }, { "controller", "Error" } });
          }
      }
}

绑定:

this.BindFilter<MyAuthorizeFilter>(System.Web.Mvc.FilterScope.Controller, 0).WhenControllerHas<MyAuthorizeAttribute>();

控制器:

[MyAuthorizeAttribute]
public class YourController : Controller
{
    // ...
}

【讨论】:

  • 您将如何设置实现以适应:[MyAuthorizeAttribute("Admin", "Contributer")]?传递参数。
  • github.com/ninject/ninject.web.mvc/wiki/Filter-configurations +1 给出支持构造函数而不是属性注入的答案
  • @Lol 编码器 - 请参阅上面 Remo 的链接了解如何配置过滤器。
  • 我仍然不知道如何设置属性构造函数来接受参数和服务。
  • 我阅读了配置......仍然无法弄清楚如何将属性构造函数参数获取到过滤器的构造函数参数......我错过了一些东西。类似问题:stackoverflow.com/questions/8305476/…
【解决方案2】:

我会高度推荐B Z's answer不要使用[Inject]

我使用了[Inject] 之类的Darin Dimitrov said 是可能的,它实际上在高负载、高争用情况下与.InRequestScope 一起导致了线程问题。

B Z's way 也是 Wiki 上的内容,我在很多地方看到 Remo GloorNinject 作者)说这是正确的做法,例如https://github.com/ninject/ninject.web.mvc/wiki/Filter-configurations.

在此处投反对票 [Inject] 回答,因为严重时您会被烧死(如果您事先没有正确加载测试,可能会在生产中!)。

【讨论】:

  • 我做了,没有人会看到它,因为它默认隐藏(太低了)。基于我花了 3 天时间试图弄清楚 Darin 的回答出了什么问题的事实,我认为它非常相关,值得一个官方回答,以避免任何人错误地使用它并被烧毁
【解决方案3】:

我找到了一个简单的解决方案,适用于 Ninject 不处理构造的任何场合:

var session = (IMyUserService)DependencyResolver.Current.GetService(typeof (IMyUserService));

实际上,这正是我在自定义AuthorizeAttribute 中使用的内容。比必须实现单独的FilterAttribute 容易得多。

【讨论】:

    【解决方案4】:

    方法是使用属性注入并使用[Inject] 属性装饰属性:

    public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
    {
        [Inject]
        public IUserService UserService { get; set; }
    
        private string[] roles;
      
        ...
    }
    

    构造函数注入不适用于属性,因为您将无法再用它们装饰控制器/动作。您只能在 Ninject 中使用带有过滤器绑定语法的构造函数注入:

    public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
    {
        private readonly IUserService userService;
    
        private string[] roles;
    
        public AuthorizeAttribute(IUserService userService, params string[] roles)
        {
            this.userService = userService;
            this.roles = roles;
        }
      
        ...
    }
    

    然后:

    internal class SiteModule : Ninject.Modules.NinjectModule
    {
        public override void Load()
        {
            Bind<IUserService>().To<UserService>();
    
            this.BindFilter<AuthorizeAttribute>(FilterScope.Controller, 0)
                .WhenControllerType<AdminController>();
        }
    }
    

    BindFilter&lt;&gt; 扩展方法在 Ninject.Web.Mvc.FilterBindingSyntax 命名空间中定义,因此请确保在内核上调用它之前已将其纳入范围。

    【讨论】:

    • 如果我不使用构造函数绑定并使用[Inject] 属性,我可以装饰控制器/动作吗?
    • 知道为什么UserService 仍然为空吗? Providers 我也有同样的问题。
    • @Lol 编码器,不知道。对我来说很好。我创建了一个新的 ASP.NET MVC 3 应用程序,安装了 NInject.MVC3 NuGet 包,声明了 IUserService 接口和 UserService 实现,使用属性注入声明了自定义 MyAuthorizeAttribute 并使用生成的 App_Start/NinjectMVC3.cs 配置内核。然后我简单地用属性装饰了我的 HomeController 并且注入工作正常。
    • 感谢您指定命名空间!!!必须找到扩展方法所需的命名空间很烦人!
    • 我强烈推荐 B Z 的答案。不要使用 [Inject] 它会在高负载下产生竞争条件!
    猜你喜欢
    • 1970-01-01
    • 2019-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多