J'essaie d'injecter la dépendance dans mon constructeur de middleware comme suit
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);
}
}
Mon fichier Startup.cs ressemble à
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseMySql(Configuration.GetConnectionString("IdentityConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
...
app.UseMiddleware<CreateCompanyMiddleware>();
...
Mais je reçois cette erreur
Une erreur s'est produite lors du démarrage de l'application. InvalidOperationException: impossible de résoudre le service de portée 'Microsoft.AspNetCore.Identity.UserManager`1 [Common.Models.ApplicationUser]' à partir du fournisseur racine. Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution (Type serviceType, IServiceScope scope, IServiceScope rootScope)
UserManager<ApplicationUser>
est (par défaut) enregistré en tant que dépendance de portée , tandis que votre middleware CreateCompanyMiddleware
est construit au démarrage de l'application (ce qui en fait un singleton ). Il s'agit d'une erreur assez standard disant que vous ne pouvez pas prendre une dépendance de portée dans un singleton classe.
La solution est simple dans ce cas - vous pouvez injecter le UserManager<ApplicationUser>
dans votre méthode Invoke
:
public async Task Invoke(HttpContext context, UserManager<ApplicationUser> userManager)
{
await _next.Invoke(context);
}
Ceci est documenté dans ASP.NET Core Middleware: dépendances du middleware par demande :
Étant donné que le middleware est construit au démarrage de l'application, et non par demande, les services de durée de vie étendus utilisés par les constructeurs de middleware ne sont pas partagés avec d'autres types injectés de dépendance au cours de chaque demande. Si vous devez partager un service de portée entre votre middleware et d'autres types, ajoutez ces services à la signature de la méthode
Invoke
. La méthodeInvoke
peut accepter des paramètres supplémentaires renseignés par DI:
Une autre façon de le faire est de créer un middleware par l'interface IMiddleware
et de l'enregistrer en tant que service
Par exemple, le 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);
}
}
et enregistrement des services:
services.AddScoped<CreateCompanyMiddlewareByInterface>();
Les middlewares utilisant IMiddleware
sont construits par 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);
}
};
});
}
ici, les codes à l'intérieur du context=>{}
sont exécutés par demande. Ainsi, chaque fois qu'il y a une demande entrante, la var middleware = middlewareFactory.Create(middlewareType);
sera exécutée puis demandera un middleware de middlewareType
(qui est déjà enregistré en tant que service) à partir de ServiceProvider
.
En ce qui concerne les middlewares par convention, aucune usine ne les crée.
Ces instances sont toutes créées par ActivatorUtilities.CreateInstance()
au démarrage. Et toute Invoke
méthode de middlewares par convention, comme
Task Invoke(HttpContext context,UserManager<ApplicationUser> userManage, ILoggerFactory loggeryFactory , ... )
sera compilé dans une fonction comme ci-dessous:
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, ...);
}
Comme vous le voyez, ici l'instance est créée au démarrage et les services de la méthode Invoke
sont demandés par requête.