webentwicklung-frage-antwort-db.com.de

Dienst in den Aktionsfilter einfügen

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>();
46
hyde

Verwendung dieser Artikel als Referenz:

ASP.NET-Hauptaktionsfilter

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.

56
Nkosi

Globale Filter

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

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>();
22
Igor Valikovsky

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))

8
A.J.Bauer

Beispiel

private ILoginService _loginService;

public override void OnActionExecuting(ActionExecutingContext context)
        {
            _loginService = (ILoginService)context.HttpContext.RequestServices.GetService(typeof(ILoginService));
        }

Ich hoffe es hilft.

3
Bukunmi

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:

0
B12Toaster