Dependency Injection mit Ninject und Filter-Attribut für asp.net mvc

Ich schreibe einen benutzerdefinierten Autorisierungsfilter für asp.net mvc 3. Ich muss einen Benutzerservice in die class injizieren, aber ich habe keine Ahnung, wie das geht.

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

Ich verwende Ninject für die Abhängigkeitsinjektion. Ich möchte kein Factory- oder Service-Locator-Muster verwenden.

Meine Bindungen sehen in der global.acsx wie folgt aus:

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

Siehe diese Antwort:

Benutzerdefinierte Autorisierung MVC 3 und Ninject IoC

Wenn Sie die Konstruktorinjektion verwenden möchten, müssen Sie ein Attribut und einen Filter erstellen.

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

Bindung:

 this.BindFilter(System.Web.Mvc.FilterScope.Controller, 0).WhenControllerHas(); 

Regler:

 [MyAuthorizeAttribute] public class YourController : Controller { } 

HTH …

Ich würde BZ’s Antwort wärmstens empfehlen. Verwenden Sie NICHT [Inject]!

Ich habe ein [Inject] wie Darin Dimitrov gesagt, war möglich und es führte tatsächlich Threading-Probleme unter hoher Last, hohe Contention-Situationen in Verbindung mit .InRequestScope.

Der Weg von BZ ist auch, was auf dem Wiki ist, und ich habe viele Orte gesehen, an denen Remo Gloor (Ninject Autor) sagt, dass dies der richtige Weg ist

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

Downvote [Inject] antwortet hier, denn ernsthaft wirst du gebrannt (wahrscheinlich in der Produktion, wenn du den Test vorher nicht richtig geladen hast!)

Auf dem Weg wäre es, eine Property-Injektion zu verwenden und die Eigenschaft mit dem Attribut [Inject] dekorieren:

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

Konstruktorinjektion funktioniert nicht gut mit Attributen, da Sie Controller / Aktionen nicht mehr mit ihnen dekorieren können. Sie können die Konstruktorinjektion nur mit der Filterbindungssyntax in NInject verwenden:

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

und dann:

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

Die BindFilter<> -Erweiterungsmethode ist im Ninject.Web.Mvc.FilterBindingSyntax Namespace definiert, also stellen Sie sicher, dass Sie diese in den Geltungsbereich gebracht haben, bevor Sie sie für einen coreel aufrufen.

Ich fand eine einfache Lösung für jede Gelegenheit, bei der die Konstruktion nicht von Ninject gehandhabt wird:

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

Das ist genau das, was ich mit meinem benutzerdefinierten AuthorizeAttribute benutze. Viel einfacher als ein separates FilterAttribute zu implementieren.