I am trying to inject dependency into my middleware constructor as follows
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); } }
My Startup.cs file looks like
public void ConfigureServices(IServiceCollection services) { services.AddDbContext<ApplicationDbContext>(options => options.UseMySql(Configuration.GetConnectionString("IdentityConnection"))); services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); ... app.UseMiddleware<CreateCompanyMiddleware>(); ...
But I am getting this error
An error occurred while starting the application. InvalidOperationException: Cannot resolve scoped service 'Microsoft.AspNetCore.Identity.UserManager`1[Common.Models.ApplicationUser]' from root provider. Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(Type serviceType, IServiceScope scope, IServiceScope rootScope)
ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies. For more information specific to dependency injection within MVC controllers, see Dependency injection into controllers in ASP.NET Core.
ASP.NET Core - Dependency Injection. ASP.NET Core is designed from scratch to support Dependency Injection. ASP.NET Core injects objects of dependency classes through constructor or method by using built-in IoC container.
Middleware are software components that are assembled into an application pipeline to handle requests and responses. Each component chooses whether to pass the request on to the next component in the pipeline, and can perform certain actions before and after the next component is invoked in the pipeline.
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. TheInvoke
method can accept additional parameters that are populated by DI:
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>();
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 .
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With