Ich versuche, einen Dienst in meinen Aktionsfilter einzuspeisen, erhalte jedoch nicht den erforderlichen Dienst im Konstruktor. Folgendes habe ich:
public class EnsureUserLoggedIn : ActionFilterAttribute
{
private readonly ISessionService _sessionService;
public EnsureUserLoggedIn()
{
// I was unable able to remove the default ctor
// because of compilation error while using the
// attribute in my controller
}
public EnsureUserLoggedIn(ISessionService sessionService)
{
_sessionService = sessionService;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
// Problem: _sessionService is null here
if (_sessionService.LoggedInUser == null)
{
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
context.Result = new JsonResult("Unauthorized");
}
}
}
Und ich dekoriere meinen Controller so:
[Route("api/issues"), EnsureUserLoggedIn]
public class IssueController : Controller
{
}
Startup.cs
services.AddScoped<ISessionService, SessionService>();
Verwendung dieser Artikel als Referenz:
Aktionsfilter, Dienstfilter und Typfilter in ASP.NET 5 und MVC 6
Verwenden des Filters als ServiceFilter
Da der Filter als ServiceType
verwendet wird, muss er beim Framework IoC registriert werden. Wenn die Aktionsfilter direkt verwendet werden, ist dies nicht erforderlich.
Startup.cs
public void ConfigureServices(IServiceCollection services) {
services.AddMvc();
services.AddScoped<ISessionService, SessionService>();
services.AddScoped<EnsureUserLoggedIn>();
...
}
Benutzerdefinierte Filter werden der MVC-Controller-Methode und der Controller-Klasse mithilfe des ServiceFilter
-Attributs wie folgt hinzugefügt:
[ServiceFilter(typeof(EnsureUserLoggedIn))]
[Route("api/issues")]
public class IssueController : Controller {
// GET: api/issues
[HttpGet]
[ServiceFilter(typeof(EnsureUserLoggedIn))]
public IEnumerable<string> Get(){...}
}
Es gab andere Beispiele von
Verwenden des Filters als globaler Filter
Verwendung des Filters mit Basiscontrollern
Verwendung des Filters bei einer Bestellung
Schauen Sie nach, probieren Sie es aus und sehen Sie, ob das Ihr Problem löst.
Hoffe das hilft.
Sie müssen IFilterFactory
implementieren:
public class AuthorizationFilterFactory : IFilterFactory
{
public bool IsReusable => false;
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
// manually find and inject necessary dependencies.
var context = (IMyContext)serviceProvider.GetService(typeof(IMyContext));
return new AuthorizationFilter(context);
}
}
In der Startup
-Klasse registrieren Sie Ihre Filter-Factory, anstatt einen tatsächlichen Filter zu registrieren:
services.AddMvc(options =>
{
options.Filters.Add(new AuthorizationFilterFactory());
});
Eine weitere Möglichkeit, dieses Problem zu lösen. Sie können Ihren Service über Context wie im folgenden Code erhalten:
public override void OnActionExecuting(ActionExecutingContext context)
{
_sessionService = context.HttpContext.RequestServices.GetService<ISessionService>();
if (_sessionService.LoggedInUser == null)
{
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
context.Result = new JsonResult("Unauthorized");
}
}
Bitte beachten Sie, dass Sie diesen Dienst in Startup.cs registrieren müssen
services.AddTransient<ISessionService, SessionService>();
Nach dem Lesen dieses Artikels ASP.NET Core - Real-World-MVC-Filter von ASP.NET Core (Aug 2016) habe ich es folgendermaßen implementiert:
In Starup.cs/ConfigureServices:
services.AddScoped<MyService>();
In MyFilterAttribute.cs:
public class MyFilterAttribute : TypeFilterAttribute
{
public MyFilterAttribute() : base(typeof (MyFilterAttributeImpl))
{
}
private class MyFilterAttributeImpl : IActionFilter
{
private readonly MyService _sv;
public MyFilterAttributeImpl(MyService sv)
{
_sv = sv;
}
public void OnActionExecuting(ActionExecutingContext context)
{
_sv.MyServiceMethod1();
}
public void OnActionExecuted(ActionExecutedContext context)
{
_sv.MyServiceMethod2();
}
}
}
In MyFooController.cs:
[MyFilter]
public IActionResult MyAction()
{
}
Bearbeiten: Das Übergeben von Argumenten wie [MyFilter("Something")]
kann mit der Arguments-Eigenschaft der TypeFilterAttribute-Klasse erfolgen: Wie füge ich einem Parameter in asp.net einen Parameter hinzu? (der Code von rboe zeigt auch, wie Dinge injiziert werden (auf die gleiche Weise))
Beispiel
private ILoginService _loginService;
public override void OnActionExecuting(ActionExecutingContext context)
{
_loginService = (ILoginService)context.HttpContext.RequestServices.GetService(typeof(ILoginService));
}
Ich hoffe es hilft.
Während sich die Frage implizit auf "Filterung über Attribute" bezieht, ist es dennoch wert, hervorzuheben, dass das Hinzufügen von Filtern "global nach Typ" DI direkt unterstützt:
[Für globale Filter, die nach Typ hinzugefügt werden] Alle Konstruktorabhängigkeiten werden durch Abhängigkeitseingabe (DI) gefüllt. Das Hinzufügen eines Filters nach Typ entspricht filter.Add (new TypeFilterAttribute (typeof (MyFilter))) . https://docs.Microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2#dependency-injection
In Bezug auf attributbasierte Filter:
Filter, die als Attribute implementiert und direkt zu Controller-Klassen oder Aktionsmethoden hinzugefügt werden, können keine Konstruktorabhängigkeiten aufweisen, die von der Abhängigkeitsinjektion (DI) bereitgestellt werden. Dies liegt daran, dass für Attribute die Konstruktorparameter dort angegeben werden müssen, wo sie angewendet werden. Dies ist eine Einschränkung der Funktionsweise von Attributen . https://docs.Microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2#dependency-injection
Wie bereits in den vorangegangenen Antworten auf das OP erwähnt, gibt es Wege der Indirektion, mit denen DI erreicht werden kann. Der Vollständigkeit halber hier die Links zu den offiziellen Dokumenten: