web-dev-qa-db-fra.com

Injection de dépendances avec l'attribut Ninject et Filter pour asp.net mvc

J'écris un filtre d'autorisation personnalisé pour asp.net mvc 3. J'ai besoin d'injecter un service utilisateur dans la classe mais je ne sais pas comment faire.

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

J'utilise ninject pour l'injection de dépendances. Je ne souhaite pas utiliser de modèle de localisateur d'usine ou de service.

Mes liaisons ressemblent à ceci dans le global.acsx:

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

Voir cette réponse:

Autorisation personnalisée MVC 3 et Ninject IoC

Si vous souhaitez utiliser l'injection de constructeur, vous devez créer un attribut et un filtre.

///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" } });
          }
      }
}

Contraignant:

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

Manette:

[MyAuthorizeAttribute]
public class YourController : Controller
{

}

HTH ...

81
B Z

Je voudrais hautement recommander la réponse de B Z. N'utilisez PAS [Inject]!

J'ai utilisé un [Inject] comme Darin Dimitrov l'a dit était possible et cela a causé des problèmes de threading sous une charge élevée, des situations de conflit élevé en conjonction avec .InRequestScope.

La manière de B Z est aussi celle qui est sur le Wiki et j'ai vu de nombreux endroits où Remo Gloor (auteur Ninject) dit que c'est la bonne façon de le faire

https://github.com/ninject/ninject.web.mvc/wiki/Filter-configurations

Downvote [Inject] répond ici car sérieusement vous serez brûlé (probablement en production si vous ne chargez pas le test correctement avant!)

11
John Culviner

J'ai trouvé une solution simple pour toute occasion où la construction n'est pas gérée par Ninject:

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

En fait, c'est exactement ce que j'utilise avec mon AuthorizeAttribute personnalisé. Beaucoup plus facile que d'avoir à implémenter un FilterAttribute distinct.

9
Wolfgang

Le chemin serait d'utiliser une injection de propriété et de décorer la propriété avec le [Inject] attribut:

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

    private string[] roles;

    ...
}

L'injection de constructeur ne fonctionne pas bien avec les attributs car vous ne pourrez plus décorer les contrôleurs/actions avec eux. Vous ne pouvez utiliser l'injection de constructeur qu'avec la syntaxe de liaison de filtre dans 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;
    }

    ...
}

puis:

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

        this.BindFilter<AuthorizeAttribute>(FilterScope.Controller, 0)
            .WhenControllerType<AdminController>();
    }
}

Le BindFilter<> la méthode d'extension est définie dans le Ninject.Web.Mvc.FilterBindingSyntax namespace donc assurez-vous d'avoir mis cela dans la portée avant de l'appeler sur un noyau.

8
Darin Dimitrov