Классы middleware в ASP.NET Core

До этого момента при изучении ASP.NET Core мы использовали компоненты middleware в форме делегатов или, так называемые inline middleware. Такой подход позволяет довольно быстро встроить компонент middleware в конвейер запросов и продемонстрировать работу приложения. При этом, стоит учитывать, что далеко не всегда компонент middleware будет содержать минимум исходного кода и выполнять одно-два действия. В этом случае рекомендуется выносить логику middleware в отдельный класс с определенным описанием.

Требования к классу middleware

Чтобы ASP.NET Core мог использовать класс, как middleware, этот класс должен соответствовать следующим требованиям:

  • Содержать открытый конструктор с параметром типа RequestDelegate.
  • Содержать открытый метод с именем Invoke или InvokeAsync, который должен:
    • вернуть Task;
    • принимать первым параметром объект типа HttpContext.

Вооружившись этими требованиями, напишем свой первый класс middleware в ASP.NET Core.

Класс middleware в ASP.NET Core

Создадим в приложении новый класс следующего содержания:

public class CharsetMiddleware
{
    private RequestDelegate _next;

    //1. открытый конструктор с парамтером типа RequestDelegate
    public CharsetMiddleware(RequestDelegate next) 
    {
        _next = next;
    }

    
    //2. открытый метод с именем InvokeAsync
    public async Task InvokeAsync(HttpContext context) 
    {
        var charset = context.Request.Query["charset"];
        context.Response.OnStarting(
                () => {
                    if (string.IsNullOrWhiteSpace(charset))
                        context.Response.ContentType = "text/plain; charset=utf-8";
                    else
                        context.Response.ContentType = $"text/plain; charset={charset}";
                    return Task.CompletedTask;
                });
        await _next(context);
    }
}

Здесь мы выполнили необходимые условия для создания класса middleware — создали открытый конструктор и метод InvokeAsync. Этот компонент middleware будет проверять параметр запроса charset и, если обнаружит его, то установит заданную в параметре кодировку текста или же укажет кодировку по умолчанию — utf-8.

Чтобы использовать этот middleware в нашем приложении мы можем воспользоваться методом UseMiddleware() следующим образом:

public static void Main(string[] args)
{
    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();

    app.UseMiddleware<CharsetMiddleware>(); //используем класс middlweare

    app.Run(async context => await context.Response.WriteAsync("Привет мир!"));

    app.Run();
}

Запустим приложение и посмотрим на результат:

кодировка по умолчанию — utf-8

меняем кодировку на KOI8-R:

Метод расширения для встраивания middleware

Несмотря на то, что для встраивания класса middleware в конвейер запросов мы можем пользоваться методом UseMiddleware, всё же рекомендуется для каждого middleware создавать метод расширения для IApplicationBuilder. Чтобы добавить метод расширения создадим новый класс следующего содержания:

public static class CharsetExtensions
{
    public static IApplicationBuilder UseCharset(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<CharsetMiddleware>();
    }
}

теперь внедрение middleware в конвейер запросов можно осуществить следующим образом:

public static void Main(string[] args)
{
    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();

    app.UseCharset(); //используем класс middlweare

    app.Run(async context => await context.Response.WriteAsync("Привет мир!"));

    app.Run();
}

Передача параметров в middleware

Изменим наш класс middleware следующим образом:

public class CharsetMiddleware
{
    private RequestDelegate _next;
    private string _defaultCharset;

    //1. открытый конструктор с парамтером типа RequestDelegate
    public CharsetMiddleware(RequestDelegate next, string defaultCharset) 
    {
        _next = next;
        _defaultCharset = defaultCharset;
    }

    
    //2. открытый метод с именем InvokeAsync
    public async Task InvokeAsync(HttpContext context) 
    {
        var charset = context.Request.Query["charset"];
        context.Response.OnStarting(
                () => {
                    if (string.IsNullOrWhiteSpace(charset))
                        context.Response.ContentType = $"text/plain; charset={_defaultCharset}";//используем кодировку указанную в параметре
                    else
                        context.Response.ContentType = $"text/plain; charset={charset}";
                    return Task.CompletedTask;
                });
        await _next(context);
    }
}

Здесь мы, в качестве второго параметра, передаем в конструктор класса значение кодировки по умолчанию и используем её, если в запросе не задан параметр charset. Соответственно, необходимо изменить и метод расширения для IApplicationBuilder

public static class CharsetExtensions
{
    public static IApplicationBuilder UseCharset(this IApplicationBuilder builder, string defaultCharset)
    {
        return builder.UseMiddleware<CharsetMiddleware>(defaultCharset);
    }
}

Здесь мы в метод UseMiddleware() передаем параметры из конструктора класса. Теперь встраивание middleware в конвейер будет выглядеть следующим образом:

public static void Main(string[] args)
{
    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();

    app.UseCharset("utf-8"); //используем класс middlweare с параметром

    app.Run(async context => await context.Response.WriteAsync("Привет мир!"));

    app.Run();
}

Итого

Сегодня мы научились создавать middleware в виде классов и внедрять эти компоненты в конвейер запросов ASP.NET Core с использованием методов расширения. Класс middleware должен обладать рядом условий, в частности, иметь открытый метод InvokeAsync.

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии