Создание конвейера запросов в ASP.NET Core с помощью WebApplication. Методы Run и Use

Как мы уже знаем, запросы в ASP.NET Core обрабатываются по принципу конвейера. В самом простейшем приложении ASP.NET Core встраивается один делегат запроса, обрабатывающий все входящие запросы. В этом случае конвейер запросов как таковой отсутствует. Вместо этого в ответ на каждый HTTP-запрос вызывается одна анонимная функция.

Терминальный компонент middleware. Метод Run

Терминальным называется компонент middleware завершающий обработку запроса. Самый простой способ создания middleware представляет метод расширения Run(), Этот метод добавляет терминальный middleware и, соответственно, Run() должен использоваться в самом конце — перед запуском приложения. Например, создадим такой терминальный компонент middleware:

public static void Main(string[] args)
{
    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    
    app.Run(async (context) => await context.Response.WriteAsync(DateTime.Now.ToShortDateString()));//терминальный middleware

    app.Run();
}

Разберемся с тем, что мы здесь написали.

Во-первых, в коде используется два разных метода Run. Первый Run() — метод расширения с помощью которого мы добавляем терминальный middleware, второй Run() — запускает наше приложение. Как только мы запускаем приложение методом Run(), то всё идёт после вызова этого метода не имеет смысла. Например, в следующем коде мы никогда не дойдем до запуска терминального middleware:

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

    app.Run(); //весь код после этой строки не имеет смысла

    app.Run(async (context) => await context.Response.WriteAsync(DateTime.Now.ToShortDateString()));//терминальный middleware
   
}

Во вторых, при создании middleware мы использовали async/await. Так как мы создаем web-приложения, то к этому приложению, в теории, могут обращаться сотни и тысячи пользователей и, чтобы наш сервер мог обрабатывать всю эту массу запросов мы используем методы асинхронного программирования. Наш компонент middleware, по сути, выполняет одну задачу — записывает в тело ответа сервера строку содержащую текущую дату. Таким образом, если запустить приложение, то мы увидим следующее:

Если предполагается, то наш компонент middleware будет выполнять несколько операций, то мы можем вынести его, например, в отдельный метод:

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

            app.Run((context)=>DateTimeWriter(context));//терминальный middleware

            app.Run();

        }

        static async Task DateTimeWriter(HttpContext context)
        {
            context.Response.Headers.ContentLanguage = "ru-RU";
            context.Response.Headers.ContentType = "text/plain; charset=utf-8";
            await context.Response.WriteAsync(DateTime.Now.ToLongDateString());
        }

    }

Здесь мы вынесли наш middleware в отдельный метод и добавили в ответ заголовки, чтобы корректно отображать русские символы. В итоге, вид приложение после запуска будет таким:

Метод Use

В отличие от метода Run, Use позволяет добавить в конвейер запросов ASP.NET Core компонент, после которого запрос будет передаваться дальше по конвейеру. Следовательно, такой компонент middleware должен получать ссылку на следующий компонент в конвейере. Например, создадим конвейер запроса, который будет формировать ответ сервера в виде небольшого html-документа, используя два middleware компонента:

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

    //первый middleware
    app.Use(async (context, next) =>
    {
        await context.Response.WriteAsync("<html><body> Welcome! <br>");
        await next.Invoke();
    });

    //второй middleware
    app.Run(async context =>
    {
        await context.Response.WriteAsync($"Current date: {DateTime.Now.ToShortDateString()}.</body></html>");
    });


    app.Run();

}

Таким образом, в первом компоненте к ответ добавляются открывающие html-теги и строка приветствия, а во второй — строка с датой и закрывающие теги. Конечно, такой конвейер с практической точки зрения малополезен, но помогает наглядно увидеть работу нескольких middleware

Итого

Сегодня мы научились создавать собственный конвейер запросов в ASP.NET Core, используя методы Use и Run для добавления очередного и замыкающего (терминального) компонента middleware в конвейер. На этом тема работы с middleware в ASP.NET Core не заканчивается. В следующей части рассмотрим вопросы, касающиеся работы с заголовками ответа в ASP.NET Core.

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