Создание компонентов middleware

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7

Последнее обновление: 30.10.2019

Кроме использования делегатов в методах Run/Use/Map мы можем создавать свои компоненты middleware в виде отдельных классов, которые затем добавляются в конвейер с помощью метода UseMiddleware(). Например, напишем свой примитивный компонент. Для этого добавим в новый проект новый класс TokenMiddleware:

using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;

public class TokenMiddleware
{
    private readonly RequestDelegate _next;

    public TokenMiddleware(RequestDelegate next)
    {
        this._next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var token = context.Request.Query["token"];
        if (token!="12345678")
        {
            context.Response.StatusCode = 403;
            await context.Response.WriteAsync("Token is invalid");
        }
        else
        {
            await _next.Invoke(context);
        }
    }
}

Класс middleware должен иметь конструктор, который принимает параметр типа RequestDelegate. Через этот параметр можно получить ссылку на тот делегат запроса, который стоит следующим в конвейере обработки запроса.

Также в классе должен быть определен метод, который должен называться либо Invoke, либо InvokeAsync. Причем этот метод должен возвращать объект Task и принимать в качестве параметра контекст запроса - объект HttpContext. Данный метод собственно и будет обрабатывать запрос.

Суть действия класса заключается в том, что мы получаем из запроса параметр "token". Если полученный токен равен строке "12345678", то передаем запрос дальше следующему компоненту, вызвав метод _next.Invoke(). Иначе возвращаем пользователю сообщение об ошибке.

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

public class Startup
{
    public void Configure(IApplicationBuilder app)
	{
        app.UseMiddleware<TokenMiddleware>();

        app.Run(async (context) =>
        {
            await context.Response.WriteAsync("Hello World");
        });
    }
}

С помощью метода UseMiddleware<T> в конструктор объекта TokenMiddleware будет внедряться объект для параметра RequestDelegate next. Поэтому явным образом передавать значение для этого параметра нам не нужно.

Запустим проект. И если мы не передадим через строку запроса параметр token или передадим для него значение, отличное от "12345678", то браузер отобразит ошибку:

Custom middleware in asp net core

Если же будет передан корректный токен, то метод app.UseToken() передаст управление методу app.Run():

Создание компонента middleware in asp net core

Также нередко для встраивания подобных компонентов middleware определяются специальные методы расширения. Так, добавим в проект новый класс, который назовем TokenExtensions:

using Microsoft.AspNetCore.Builder;
public static class TokenExtensions
{
    public static IApplicationBuilder UseToken(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<TokenMiddleware>();
    }
}

Здесь создается метод расширения для типа IApplicationBuilder. И этот метод встраивает компонент TokenMiddleware в конвейер обработки запроса. Как правило, подобные методы возвращают объект IApplicationBuilder.

Таким образом, у нас получится следующая структура проекта:

Custom middleware in ASP.NET Core

Теперь применим этот метод в методе Configure() класса Startup:

public class Startup
{
    public void Configure(IApplicationBuilder app)
	{
        app.UseToken();

        app.Run(async (context) =>
        {
            await context.Response.WriteAsync("Hello World");
        });
    }
}

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

Изменим класс TokenMiddleware, чтобы он извне получал образец токена для сравнения:

using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;

public class TokenMiddleware
{
    private readonly RequestDelegate _next;
	string pattern;
    public TokenMiddleware(RequestDelegate next, string pattern)
    {
        this._next = next;
        this.pattern = pattern;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var token = context.Request.Query["token"];
        if (token!=pattern)
        {
            context.Response.StatusCode = 403;
            await context.Response.WriteAsync("Token is invalid");
        }
        else
        {
            await _next.Invoke(context);
        }
    }
}

Образец токена, с которым идет сравнения, устанавливается через конструктор. Чтобы передать его в конструктор, изменим класс TokenExtensions:

using Microsoft.AspNetCore.Builder;
public static class TokenExtensions
{
    public static IApplicationBuilder UseToken(this IApplicationBuilder builder, string pattern)
    {
        return builder.UseMiddleware<TokenMiddleware>(pattern);
    }
}

В метод builder.UseMiddleware можно передать набор значений, которые передаются в конструктор компонента middleware.

Затем в методе Configure() уже можно передать в метод расширения UseToken конкретное значение:

public void Configure(IApplicationBuilder app)
{
    app.UseToken("555555");
            
    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello World");
    });
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850