Активация компонентов промежуточного ПО через фабрику в ASP.NET Core

Note

Это не последняя версия этой статьи. В текущей версии см. версию .NET 10 этой статьи.

Warning

Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. В текущей версии см. версию .NET 10 этой статьи.

IMiddlewareFactory / IMiddleware — это точка расширяемости для активации middleware, обеспечивающая следующие преимущества:

  • Активация по клиентскому запросу (внедрение ограниченных служб)
  • Строгая типизация промежуточного ПО

Методы расширения UseMiddleware проверяют, реализует ли зарегистрированный тип промежуточного ПО интерфейс IMiddleware. Если да, то экземпляр IMiddlewareFactory, зарегистрированный в контейнере, используется для разрешения реализации IMiddleware вместо стандартной логики активации ПО промежуточного слоя. ПО промежуточного слоя регистрируется как ограниченная (scoped) или временная (temporary) служба в контейнере служб приложения.

IMiddleware активируется по запросу клиента (соединению), поэтому сервисы с областью действия scoped можно внедрять через конструктор промежуточного ПО.

IMiddleware

IMiddleware определяет промежуточное ПО в конвейере обработки запросов приложения. Метод InvokeAsync(HttpContext, RequestDelegate) обрабатывает запрос и возвращает объект Task, который представляет выполнение ПО промежуточного слоя.

Промежуточное ПО, активируемое по соглашению:

public class ConventionalMiddleware
{
    private readonly RequestDelegate _next;

    public ConventionalMiddleware(RequestDelegate next)
        => _next = next;

    public async Task InvokeAsync(HttpContext context, SampleDbContext dbContext)
    {
        var keyValue = context.Request.Query["key"];

        if (!string.IsNullOrWhiteSpace(keyValue))
        {
            dbContext.Requests.Add(new Request("Conventional", keyValue));

            await dbContext.SaveChangesAsync();
        }

        await _next(context);
    }
}

Активация ПО промежуточного слоя с помощью MiddlewareFactory:

public class FactoryActivatedMiddleware : IMiddleware
{
    private readonly SampleDbContext _dbContext;

    public FactoryActivatedMiddleware(SampleDbContext dbContext)
        => _dbContext = dbContext;

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        var keyValue = context.Request.Query["key"];

        if (!string.IsNullOrWhiteSpace(keyValue))
        {
            _dbContext.Requests.Add(new Request("Factory", keyValue));

            await _dbContext.SaveChangesAsync();
        }

        await next(context);
    }
}

Расширения, создаваемые для ПО промежуточного слоя:

public static class MiddlewareExtensions
{
    public static IApplicationBuilder UseConventionalMiddleware(
        this IApplicationBuilder app)
        => app.UseMiddleware<ConventionalMiddleware>();

    public static IApplicationBuilder UseFactoryActivatedMiddleware(
        this IApplicationBuilder app)
        => app.UseMiddleware<FactoryActivatedMiddleware>();
}

Невозможно передавать объекты промежуточному ПО, активируемому фабрикой, с помощью UseMiddleware:

public static IApplicationBuilder UseFactoryActivatedMiddleware(
    this IApplicationBuilder app, bool option)
{
    // Passing 'option' as an argument throws a NotSupportedException at runtime.
    return app.UseMiddleware<FactoryActivatedMiddleware>(option);
}

Промежуточное ПО, активируемое фабрикой, добавляется во встроенный контейнер в Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<SampleDbContext>
    (options => options.UseInMemoryDatabase("SampleDb"));

builder.Services.AddTransient<FactoryActivatedMiddleware>();

Оба компонента middleware зарегистрированы в конвейере обработки запросов, а также в Program.cs:

var app = builder.Build();

app.UseConventionalMiddleware();
app.UseFactoryActivatedMiddleware();

IMiddlewareFactory

IMiddlewareFactory предоставляет методы для создания ПО промежуточного слоя. Реализация фабрики middleware регистрируется в контейнере как служба с областью действия.

Реализация IMiddlewareFactory по умолчанию, MiddlewareFactory, находится в пакете Microsoft.AspNetCore.Http.

Дополнительные ресурсы

IMiddlewareFactory / IMiddleware — это точка расширения для активации промежуточного ПО.

Методы расширения UseMiddleware проверяют, реализует ли зарегистрированный тип промежуточного ПО интерфейс IMiddleware. Если да, то экземпляр IMiddlewareFactory, зарегистрированный в контейнере, используется для разрешения реализации IMiddleware вместо стандартной логики активации ПО промежуточного слоя. ПО промежуточного слоя регистрируется как ограниченная (scoped) или временная (temporary) служба в контейнере служб приложения.

Benefits:

  • Активация по запросу клиента (внедрение сервисов с ограниченной областью действия)
  • Строгая типизация промежуточного ПО

IMiddleware активируется для каждого клиентского запроса (соединения), поэтому сервисы с областью действия scoped можно внедрять в конструктор промежуточного ПО.

Просмотреть или скачать образец кода (описание загрузки)

IMiddleware

IMiddleware определяет промежуточное ПО в конвейере обработки запросов приложения. Метод InvokeAsync(HttpContext, RequestDelegate) обрабатывает запрос и возвращает объект Task, который представляет выполнение ПО промежуточного слоя.

Промежуточное ПО, активируемое по соглашению:

public class ConventionalMiddleware
{
    private readonly RequestDelegate _next;

    public ConventionalMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context, AppDbContext db)
    {
        var keyValue = context.Request.Query["key"];

        if (!string.IsNullOrWhiteSpace(keyValue))
        {
            db.Add(new Request()
                {
                    DT = DateTime.UtcNow, 
                    MiddlewareActivation = "ConventionalMiddleware", 
                    Value = keyValue
                });

            await db.SaveChangesAsync();
        }

        await _next(context);
    }
}

Активация ПО промежуточного слоя с помощью MiddlewareFactory:

public class FactoryActivatedMiddleware : IMiddleware
{
    private readonly AppDbContext _db;

    public FactoryActivatedMiddleware(AppDbContext db)
    {
        _db = db;
    }

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        var keyValue = context.Request.Query["key"];

        if (!string.IsNullOrWhiteSpace(keyValue))
        {
            _db.Add(new Request()
                {
                    DT = DateTime.UtcNow, 
                    MiddlewareActivation = "FactoryActivatedMiddleware", 
                    Value = keyValue
                });

            await _db.SaveChangesAsync();
        }

        await next(context);
    }
}

Расширения, создаваемые для ПО промежуточного слоя:

public static class MiddlewareExtensions
{
    public static IApplicationBuilder UseConventionalMiddleware(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<ConventionalMiddleware>();
    }

    public static IApplicationBuilder UseFactoryActivatedMiddleware(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<FactoryActivatedMiddleware>();
    }
}

Невозможно передавать объекты в промежуточное ПО, активируемое фабрикой, через UseMiddleware:

public static IApplicationBuilder UseFactoryActivatedMiddleware(
    this IApplicationBuilder builder, bool option)
{
    // Passing 'option' as an argument throws a NotSupportedException at runtime.
    return builder.UseMiddleware<FactoryActivatedMiddleware>(option);
}

Во встроенный контейнер в Startup.ConfigureServices добавляется промежуточное ПО, активируемое через фабрику.

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<AppDbContext>(options =>
        options.UseInMemoryDatabase("InMemoryDb"));

    services.AddTransient<FactoryActivatedMiddleware>();

    services.AddRazorPages();
}

Оба компонента промежуточного ПО регистрируются в конвейере обработки запросов в Startup.Configure:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
    }

    app.UseConventionalMiddleware();
    app.UseFactoryActivatedMiddleware();

    app.UseStaticFiles();
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

IMiddlewareFactory

IMiddlewareFactory предоставляет методы для создания ПО промежуточного слоя. Реализация фабрики промежуточного ПО регистрируется в контейнере как сервис с областью действия scoped.

Реализация IMiddlewareFactory по умолчанию, MiddlewareFactory, находится в пакете Microsoft.AspNetCore.Http.

Дополнительные ресурсы

IMiddlewareFactory / IMiddleware — это точка расширения для активации промежуточного ПО.

Методы расширения UseMiddleware проверяют, реализует ли зарегистрированный тип промежуточного ПО интерфейс IMiddleware. Если да, то экземпляр IMiddlewareFactory, зарегистрированный в контейнере, используется для разрешения реализации IMiddleware вместо стандартной логики активации ПО промежуточного слоя. ПО промежуточного слоя регистрируется как ограниченная (scoped) или временная (temporary) служба в контейнере служб приложения.

Benefits:

  • Активация по запросу клиента (внедрение сервисов с ограниченной областью действия)
  • Строгая типизация промежуточного ПО

IMiddleware активируется для каждого клиентского запроса (соединения), поэтому сервисы с областью действия scoped можно внедрять в конструктор промежуточного ПО.

Просмотреть или скачать образец кода (описание загрузки)

IMiddleware

IMiddleware определяет промежуточное ПО в конвейере обработки запросов приложения. Метод InvokeAsync(HttpContext, RequestDelegate) обрабатывает запрос и возвращает объект Task, который представляет выполнение ПО промежуточного слоя.

Промежуточное ПО, активируемое по соглашению:

public class ConventionalMiddleware
{
    private readonly RequestDelegate _next;

    public ConventionalMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context, AppDbContext db)
    {
        var keyValue = context.Request.Query["key"];

        if (!string.IsNullOrWhiteSpace(keyValue))
        {
            db.Add(new Request()
                {
                    DT = DateTime.UtcNow, 
                    MiddlewareActivation = "ConventionalMiddleware", 
                    Value = keyValue
                });

            await db.SaveChangesAsync();
        }

        await _next(context);
    }
}

Активация ПО промежуточного слоя с помощью MiddlewareFactory:

public class FactoryActivatedMiddleware : IMiddleware
{
    private readonly AppDbContext _db;

    public FactoryActivatedMiddleware(AppDbContext db)
    {
        _db = db;
    }

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        var keyValue = context.Request.Query["key"];

        if (!string.IsNullOrWhiteSpace(keyValue))
        {
            _db.Add(new Request()
                {
                    DT = DateTime.UtcNow, 
                    MiddlewareActivation = "FactoryActivatedMiddleware", 
                    Value = keyValue
                });

            await _db.SaveChangesAsync();
        }

        await next(context);
    }
}

Расширения, создаваемые для ПО промежуточного слоя:

public static class MiddlewareExtensions
{
    public static IApplicationBuilder UseConventionalMiddleware(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<ConventionalMiddleware>();
    }

    public static IApplicationBuilder UseFactoryActivatedMiddleware(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<FactoryActivatedMiddleware>();
    }
}

Невозможно передавать объекты в промежуточное ПО, активируемое фабрикой, через UseMiddleware:

public static IApplicationBuilder UseFactoryActivatedMiddleware(
    this IApplicationBuilder builder, bool option)
{
    // Passing 'option' as an argument throws a NotSupportedException at runtime.
    return builder.UseMiddleware<FactoryActivatedMiddleware>(option);
}

Во встроенный контейнер в Startup.ConfigureServices добавляется промежуточное ПО, активируемое через фабрику.

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<AppDbContext>(options =>
        options.UseInMemoryDatabase("InMemoryDb"));

    services.AddTransient<FactoryActivatedMiddleware>();

    services.AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

Оба компонента промежуточного ПО регистрируются в конвейере обработки запросов в Startup.Configure:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
    }

    app.UseConventionalMiddleware();
    app.UseFactoryActivatedMiddleware();

    app.UseStaticFiles();
    app.UseMvc();
}

IMiddlewareFactory

IMiddlewareFactory предоставляет методы для создания ПО промежуточного слоя. Реализация фабрики промежуточного ПО регистрируется в контейнере как сервис с областью действия scoped.

Реализация IMiddlewareFactory по умолчанию, MiddlewareFactory, находится в пакете Microsoft.AspNetCore.Http.

Дополнительные ресурсы