Я пытаюсь ввести зависимость в свой конструктор промежуточного программного обеспечения следующим образом
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);
}
}
Мой файл Startup.cs выглядит так
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseMySql(Configuration.GetConnectionString("IdentityConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
...
app.UseMiddleware<CreateCompanyMiddleware>();
...
Но я получаю эту ошибку
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)





UserManager<ApplicationUser> (по умолчанию) зарегистрирован как зависимость ограниченный, тогда как промежуточное ПО CreateCompanyMiddleware создается при запуске приложения (фактически делая его одиночка). Это довольно стандартная ошибка, говорящая о том, что вы не можете включить зависимость ограниченный в класс одиночка.
В этом случае исправить просто - вы можете вставить UserManager<ApplicationUser> в свой метод Invoke:
public async Task Invoke(HttpContext context, UserManager<ApplicationUser> userManager)
{
await _next.Invoke(context);
}
Это задокументировано в ПО промежуточного слоя ASP.NET Core: зависимости промежуточного ПО для каждого запроса:
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
Invokemethod's signature. TheInvokemethod can accept additional parameters that are populated by DI:
Другой способ сделать это - создать промежуточное ПО через интерфейс IMiddleware и зарегистрировать его как службу.
Например, промежуточное ПО
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);
}
}
и регистрация услуги:
services.AddScoped<CreateCompanyMiddlewareByInterface>();
Промежуточное ПО, использующее IMiddleware, построено на 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);
}
};
});
}
здесь коды внутри context=>{} выполняются по запросу. Таким образом, каждый раз, когда появляется входящий запрос, var middleware = middlewareFactory.Create(middlewareType); будет выполняться, а затем запрашивать промежуточное ПО для middlewareType (которое уже зарегистрировано как служба) у ServiceProvider.
Что касается промежуточного программного обеспечения по соглашению, фабрика их не создаёт.
Все эти экземпляры создаются ActivatorUtilities.CreateInstance() во время запуска. И любой метод Invoke промежуточного программного обеспечения по соглашению, такой как
Task Invoke(HttpContext context,UserManager<ApplicationUser> userManage, ILoggerFactory loggeryFactory , ... )
будет скомпилирован в функцию, как показано ниже:
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, ...);
}
Как видите, здесь экземпляр создается во время запуска, и эти службы метода Invoke запрашиваются по запросу.
Заводской подход описан здесь: docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware /…
Хорошее простое решение, которое сработало для меня. Обратите внимание: если вы забудете добавить классы DI в startup.cs, тогда ошибки в промежуточном программном обеспечении не всегда будут отображаться на экране, и точки останова не будут задействованы. Может показаться, что код работает, но, скорее всего, это не так.