[Программирование, .NET, ASP, C#] Разбираемся с middleware в ASP.NET Core (перевод)

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
18-Ноя-2020 23:30
В преддверии курса "C# ASP.NET Core разработчик" приглашаем вас записаться на открытый урок по теме "Логирование и трейсинг запросов в asp.net core".
А пока делимся с вами традиционным полезным переводом.

Этой статья раскрывает концепции Middleware в ASP.NET Core. К концу этой статьи вы получите четкое представление о следующих моментах:
  • Что такое Middleware?
  • Почему порядок расположения Middleware имеет значение?
  • Методы Run, Use и Map.
  • Как создать собственное Middleware?
  • Как реализовать просмотр каталогов с помощью Middleware?
Что такое Middleware?Middleware (промежуточное или связующее программное обеспечение) — это фрагмент кода в конвейере приложения, используемый для обработки запросов и ответов.Например, у нас может быть middleware-компонент для аутентификации пользователя, middleware-компонент для обработки ошибок и еще один middleware-компонент для обслуживания статических файлов, таких как файлы JavaScript, CSS, разного рода изображения и т. д. Middleware может быть встроенным как часть платформы .NET Core, добавляемым через пакеты NuGet или же написанным самим пользователем. Middleware-компоненты настраиваются в методе Сonfigure класса запуска приложения (Startup). Метод Configure выстраивает конвейер обработки запросов в ASP.NET Core приложении. Он состоит из последовательности делегатов запросов, вызываемых один за другим. На рисунке ниже показано, как запрос обрабатывается middleware-компонентами.
Как правило, каждое middleware обрабатывает входящие запросы и передает выполнение следующему middleware для дальнейшей обработки.Но middleware-компонент также может решить не вызывать следующую часть middleware в конвейере. Это называется замыканием (short-circuiting) или завершением конвейера запросов. Замыкание зачастую желательно, поскольку оно позволяет избежать ненужной работы. Например, если это запрос статического файла, такого как файл CSS, JavaScript, изображение и т. д., middleware-компонент для статических файлов может обработать и обслужить этот запрос, а затем замкнуть остальную часть конвейера. Давайте создадим ASP.NET Core веб-приложение и рассмотрим конфигурацию middleware по умолчанию в методе Configure класса Startup.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        //This middleware is used reports app runtime errors in development environment.
        app.UseDeveloperExceptionPage();
    }
    else
    {
        //This middleware is catches exceptions thrown in production environment.
        app.UseExceptionHandler("/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts(); //adds the Strict-Transport-Security header.
    }
    //This middleware is used to redirects HTTP requests to HTTPS.
    app.UseHttpsRedirection();
    //This middleware is used to returns static files and short-circuits further request processing.
    app.UseStaticFiles();
    //This middleware is used to route requests.
    app.UseRouting();
    //This middleware is used to authorizes a user to access secure resources.
    app.UseAuthorization();
    //This middleware is used to add Razor Pages endpoints to the request pipeline.
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}
Фреймворк ASP.NET Core предоставляет встроенные middleware-компоненты, которые мы можем легко использовать, добавляя в метод Configure. Ознакомьтесь с документацией Microsoft для получения более подробной информации.Упорядочение MiddlewareMiddleware-компоненты выполняются в том порядке, в котором они добавляются в конвейер, по этому следует проявлять осторожность и добавлять middleware в правильном порядке, иначе приложение может работать не так, как вы ожидаете. Порядок расположения middleware важен для безопасности, производительности и функциональности.Следующие middleware-компоненты предназначены для стандартных сценариев приложений и расположены в рекомендуемом порядке:
Первый middleware-компонент в конфигурации получил запрос, изменил его (при необходимости) и передал управление следующему middleware. Точно так же первый middleware-компонент выполняется последним при обработке ответа, если мы возвращаем обратно эхо. Вот почему делегаты обработки исключений должны вызываться на самых ранних этапах конвейера - чтобы они могли проверить результат и отобразить возможное исключение в удобном для браузера и клиента виде.Методы Run, Use и Mapapp.Run()Этот метод добавляет middleware-компонент в виде Run[Middleware], который выполнится в конце конвейера. Как правило, он действует как замыкающее middleware и добавляется в конце конвейера запросов, поскольку не может вызывать следующий middleware-компонент. app.Use() Этот метод используется для конфигурирования нескольких middleware. В отличие от app.Run(), мы можем включить в него параметр next, который вызывает следующий делегат запроса в конвейере. Мы также можем замкнуть (завершить) конвейер, не вызывая параметр next.  Давайте рассмотрим следующий пример с app.Use() и app.Run() и проанализируем результат/ответ:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.Use(async (context, next) =>
    {
        await context.Response.WriteAsync("Before Invoke from 1st app.Use()\n");
        await next();
        await context.Response.WriteAsync("After Invoke from 1st app.Use()\n");
    });
    app.Use(async (context, next) =>
    {
        await context.Response.WriteAsync("Before Invoke from 2nd app.Use()\n");
        await next();
        await context.Response.WriteAsync("After Invoke from 2nd app.Use()\n");
    });
    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello from 1st app.Run()\n");
    });
    // the following will never be executed
    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello from 2nd app.Run()\n");
    });
}

Первый делегат app.Run() завершает конвейер. В этом примере будет запущен только первый делегат («Hello from 1st app.Run()»), а запрос никогда не достигнет второго метода Run.app.Map()Этот метод расширения используются как условное обозначение для ветвления конвейера. Map разветвляет конвейер запросов на основе пути запроса. Если путь запроса начинается с указанного пути, ветвь выполняется.Давайте рассмотрим следующий пример с app.Map() и проанализируем результат/ответ:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.Map("/m1", HandleMapOne);
    app.Map("/m2", appMap => {
        appMap.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from 2nd app.Map()");
        });
    });
    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello from app.Run()");
    });
}
private static void HandleMapOne(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Hello from 1st app.Map()");
    });
}
В следующей таблице показаны запросы и ответы от localhost с использованием приведенного выше кода.RequestResponsehttps://localhost:44362/Hello from app.Run()https://localhost:44362/m1Hello from 1st app.Map()https://localhost:44362/m1/xyzHello from 1st app.Map()https://localhost:44362/m2Hello from 2nd app.Map()https://localhost:44362/m500Hello from app.Run()Создание собственного MiddlewareMiddleware обычно инкапсулируется в класс и предоставляется с помощью метода расширения. Middleware может быть создано с помощью класса с методом InvokeAsync() и параметром типа RequestDelegate в конструкторе. Тип RequestDelegate требуется для выполнения следующего middleware в последовательности.Рассмотрим пример, в котором нам нужно создать собственное middleware для регистрации URL-адреса запроса в веб-приложении.
public class LogURLMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<LogURLMiddleware> _logger;
    public LogURLMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
    {
        _next = next;
        _logger = loggerFactory?.CreateLogger<LogURLMiddleware>() ??
        throw new ArgumentNullException(nameof(loggerFactory));
    }
    public async Task InvokeAsync(HttpContext context)
    {
        _logger.LogInformation($"Request URL: {Microsoft.AspNetCore.Http.Extensions.UriHelper.GetDisplayUrl(context.Request)}");
        await this._next(context);
    }
}
public static class LogURLMiddlewareExtensions
{
    public static IApplicationBuilder UseLogUrl(this IApplicationBuilder app)
    {
        return app.UseMiddleware<LogURLMiddleware>();
    }
}
В методе Configure:
app.UseLogUrl();
Реализация просмотра каталогов с помощью Middleware Просмотр каталогов позволяет пользователям вашего веб-приложения видеть собственно сам список каталогов и файлы. Просмотр каталогов по умолчанию отключен из соображений безопасности. Давайте рассмотрим пример, в котором мы хотим реализовать просмотр списка изображений в браузере из папки с изображениями в wwwroot. Middleware UseDirectoryBrowser может обрабатывать и обслуживать эти изображения для такого рода запросов, а затем замкнуть остальную часть конвейера.
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images")),
    RequestPath = "/images"
});

Резюме Middleware в ASP.NET Core контролирует, как наше приложение отвечает на HTTP-запросы. Таким образом, каждый middleware-компонент в ASP.NET Core:
  • Имеет доступ как к входящим запросам, так и к отправляемым обратно ответам.
  • Может просто передать запрос следующему middleware в конвейере.
  • Может выполнять некоторую логику обработки и затем передавать этот запрос следующему middleware для дальнейшей обработки.
  • При необходимости может завершить (замкнуть) конвейер запросов.
  • Выполняется в том порядке, в котором он был добавлены в конвейер.
Надеюсь, вы что-нибудь для себя почерпнули из этой статьи! Удачи вам в обучении!
Узнать подробнее о курсе и записаться на открытый урок можно здесь.

===========
Источник:
habr.com
===========

===========
Автор оригинала: Anupam Maiti
===========
Похожие новости: Теги для поиска: #_programmirovanie (Программирование), #_.net, #_asp, #_c#, #_middleware, #_asp.net_core, #_c#, #_blog_kompanii_otus._onlajnobrazovanie (
Блог компании OTUS. Онлайн-образование
)
, #_programmirovanie (
Программирование
)
, #_.net, #_asp, #_c#
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 25-Ноя 11:25
Часовой пояс: UTC + 5