wake-up-neo.com

Wie mache ich DI in asp.net Core Middleware?

Ich versuche, die Abhängigkeit wie folgt in meinen Middleware-Konstruktor einzufügen

public class CreateCompanyMiddleware
{
    private readonly RequestDelegate _next;
    private readonly UserManager<ApplicationUser> _userManager;

    public CreateCompanyMiddleware(RequestDelegate next
        , UserManager<ApplicationUser> userManager
        )
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        await _next.Invoke(context);
    }
}

Meine Startup.cs-Datei sieht aus wie

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseMySql(Configuration.GetConnectionString("IdentityConnection")));

    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();
    ...

    app.UseMiddleware<CreateCompanyMiddleware>();

    ...

Aber ich bekomme diesen Fehler

Beim Starten der Anwendung ist ein Fehler aufgetreten. InvalidOperationException: Der Dienst 'Microsoft.AspNetCore.Identity.UserManager`1 [Common.Models.ApplicationUser]' kann nicht vom Root-Anbieter aufgelöst werden. Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution (Typ serviceType, IServiceScope-Bereich, IServiceScope rootScope)

26
Yasser Shaikh

UserManager<ApplicationUser> Ist (standardmäßig) als Gültigkeitsbereich Abhängigkeit registriert, während Ihre CreateCompanyMiddleware Middleware beim Start der App erstellt wird (was sie effektiv zu einem Singleton macht) ). Dies ist ein ziemlich normaler Fehler, der besagt, dass Sie eine Gültigkeitsbereich Abhängigkeit nicht in eine Singleton Klasse aufnehmen können.

Das Update ist in diesem Fall einfach: Sie können UserManager<ApplicationUser> In Ihre Invoke -Methode einfügen:

public async Task Invoke(HttpContext context, UserManager<ApplicationUser> userManager)
{
    await _next.Invoke(context);
}

Dies ist dokumentiert in ASP.NET Core Middleware: Middleware-Abhängigkeiten pro Anforderung :

Da Middleware beim Start der App erstellt wird, nicht pro Anforderung, werden Gültigkeitsbereich Lebensdauerdienste, die von Middleware-Konstruktoren verwendet werden, nicht bei jeder Anforderung mit anderen Typen mit Abhängigkeitsinjektion geteilt. Wenn Sie einen Gültigkeitsbereich Dienst zwischen Ihrer Middleware und anderen Typen freigeben müssen, fügen Sie diese Dienste der Signatur der Invoke -Methode hinzu. Die Methode Invoke kann zusätzliche Parameter akzeptieren, die von DI ausgefüllt werden:

58
Kirk Larkin

Eine andere Möglichkeit, dies zu tun, besteht darin, eine Middleware über die Schnittstelle IMiddleware zu erstellen und als Dienst zu registrieren

Zum Beispiel die Middleware

public class CreateCompanyMiddlewareByInterface : IMiddleware
{
    private readonly UserManager<ApplicationUser> _userManager;

    public CreateCompanyMiddlewareByInterface(UserManager<ApplicationUser> userManager )
    {
        this._userManager = userManager;
    }


    public Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        return next(context);
    }
} 

und Serviceregistrierung:

services.AddScoped<CreateCompanyMiddlewareByInterface>();
  1. Warum passiert es?

Die Middlewares, die IMiddleware verwenden, werden von UseMiddlewareInterface(appBuilder, middlewareType type) erstellt:

private static IApplicationBuilder UseMiddlewareInterface(IApplicationBuilder app, Type middlewareType)
{
    return app.Use(next =>
    {
        return async context =>
        {
            var middlewareFactory = (IMiddlewareFactory)context.RequestServices.GetService(typeof(IMiddlewareFactory));
            if (middlewareFactory == null) { /* throw ... */ }

            var middleware = middlewareFactory.Create(middlewareType);
            if (middleware == null) { /* throw ... */ }

            try{
                await middleware.InvokeAsync(context, next);
            }
            finally{
                middlewareFactory.Release(middleware);
            }
        };
    });
}

hier werden die Codes im context=>{} pro Anfrage ausgeführt. Jedes Mal, wenn eine eingehende Anforderung eingeht, wird die Funktion var middleware = middlewareFactory.Create(middlewareType); ausgeführt und fordert dann eine Middleware von middlewareType (die bereits als Dienst registriert ist) von ServiceProvider an.

Konventionelle Middlewares werden von keiner Fabrik hergestellt.

Diese Instanzen werden alle beim Start von ActivatorUtilities.CreateInstance() erstellt. Und jede Invoke Methode von Konventions-Middlewares, wie z

Task Invoke(HttpContext context,UserManager<ApplicationUser> userManage, ILoggerFactory loggeryFactory , ... )

wird in eine Funktion wie folgt kompiliert:

Task Invoke(Middleware instance, HttpContext httpContext, IServiceprovider provider)
{
    var useManager  /* = get service from service provider */ ;
    var log = /* = get service from service provider */ ;
    // ... 
    return instance.Invoke(httpContext,userManager,log, ...);
}

Wie Sie sehen, wird hier die Instanz beim Start erstellt, und die Dienste der Methode Invoke werden pro Anforderung angefordert.

11
itminus