How to do DI in asp.net core middleware?

后端 未结 2 766
时光说笑
时光说笑 2020-12-08 13:29

I am trying to inject dependency into my middleware constructor as follows

public class CreateCompanyMiddleware
{
    private readonly RequestDelegate _next;         


        
相关标签:
2条回答
  • 2020-12-08 13:48

    UserManager<ApplicationUser> is (by default) registered as a scoped dependency, whereas your CreateCompanyMiddleware middleware is constructed at app startup (effectively making it a singleton). This is a fairly standard error saying that you can't take a scoped dependency into a singleton class.

    The fix is simple in this case - you can inject the UserManager<ApplicationUser> into your Invoke method:

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

    This is documented in ASP.NET Core Middleware: Per-request middleware dependencies:

    Because middleware is constructed at app startup, not per-request, scoped lifetime services used by middleware constructors aren't shared with other dependency-injected types during each request. If you must share a scoped service between your middleware and other types, add these services to the Invoke method's signature. The Invoke method can accept additional parameters that are populated by DI:

    0 讨论(0)
  • 2020-12-08 13:48

    Another way to do that is to create a middleware by IMiddleware interface and register it as a service

    For example , the 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);
        }
    } 
    

    and service registeration :

    services.AddScoped<CreateCompanyMiddlewareByInterface>();
    
    1. So why it happens ?

    The middlewares using IMiddleware are built by UseMiddlewareInterface(appBuilder, middlewareType type) :

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

    here the codes inside the context=>{} are executed per-request . So every time there's an incoming request , the var middleware = middlewareFactory.Create(middlewareType); will be executed and then ask for a middleware of middlewareType ( which is already registered as a service ) from the ServiceProvider .

    As for by-convention middlewares , there's no factory creating them .

    Those instances are all created by ActivatorUtilities.CreateInstance() at startup time . And any Invoke method of by-convention middlewares , such as

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

    will be compiled into a function like below :

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

    As you see , here the instance is created at startup time , and those services of Invoke method are requested per request .

    0 讨论(0)
提交回复
热议问题