Как сделать DI в промежуточном программном обеспечении ядра asp.net? - PullRequest
0 голосов
/ 06 сентября 2018

Я пытаюсь внедрить зависимость в конструктор промежуточного программного обеспечения следующим образом

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

    ...

Но я получаю эту ошибку

Произошла ошибка при запуске приложения. InvalidOperationException: Невозможно разрешить определенную службу «Microsoft.AspNetCore.Identity.UserManager`1 [Common.Models.ApplicationUser]» от корневого поставщика. Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution (Тип serviceType, область IServiceScope, IServiceScope rootScope)

Ответы [ 2 ]

0 голосов
/ 07 сентября 2018

Еще один способ сделать это - создать промежуточное ПО с помощью интерфейса 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>();
  1. Так почему же это происходит?

Промежуточное программное обеспечение, использующее 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 запрашиваются для каждого запроса.

0 голосов
/ 06 сентября 2018

UserManager<ApplicationUser> (по умолчанию) зарегистрирован как область действия , в то время как ваше промежуточное программное обеспечение CreateCompanyMiddleware создается при запуске приложения (эффективно превращая его в singleton ). Это довольно стандартная ошибка, говорящая о том, что вы не можете принять зависимость scoped в singleton класс.

В данном случае это просто: вы можете добавить UserManager<ApplicationUser> в ваш Invoke метод:

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

Это задокументировано в Промежуточное программное обеспечение ядра ASP.NET: зависимости промежуточного программного обеспечения по запросу :

Поскольку промежуточное ПО создается при запуске приложения, а не по запросу, ограниченные службы времени жизни, используемые конструкторами промежуточного ПО, не используются совместно с другими типами, внедренными зависимостями, во время каждого запроса. Если вам необходимо совместно использовать службу scoped между промежуточным программным обеспечением и другими типами, добавьте эти службы в подпись метода Invoke. Метод Invoke может принимать дополнительные параметры, которые заполняются DI:

...