Создание ветки конвейера. UseWhen и MapWhen

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

UseWhen

Метод UseWhen() в зависимости от некоторого условия позволяет создать ответвление конвейера при обработке запроса:

UseWhen (predicate As Func(Of HttpContext, Boolean), configuration As Action(Of IApplicationBuilder))

Как и Use(), метод UseWhen() реализован как метод расширения для типа IApplicationBuilder.

В качестве параметра он принимает делегат Func(Of HttpContext, Boolean) - некоторое условие, которому должен соответствовать запрос. В этот делегат передается объект HttpContext. А возвращаемым типом должен быть тип Boolean - если запрос соответствует условию, то возвращается True, иначе возвращаеся false.

Последний параметр метода - делегат Action(Of IApplicationBuilder) представляет некоторые действия над объектом IApplicationBuilder, который передается в делегат в качестве параметра.

Рассмотрим небольшой пример:

Imports Microsoft.AspNetCore.Builder
Imports Microsoft.AspNetCore.Http

Module Program
    Sub Main(args As String())

        Dim builder = WebApplication.CreateBuilder(args)
        Dim app = builder.Build()

        app.UseWhen(Function(context) context.Request.Path.Value = "/time", ' если путь запроса "/time"
        Sub(appBuilder)
            'логгируем данные - выводим на консоль приложения
            appBuilder.Use(Async Function(context, nextMiddleware) As Task

                               Dim time = Now.ToShortTimeString()
                               Console.WriteLine($"Time: {time}")
                               Await nextMiddleware() 'вызываем следующий middleware
                           End Function)
            'отправляем ответ
            appBuilder.Run(Async Function(context) As Task
                               Dim time = Now.ToShortTimeString()
                               Await context.Response.WriteAsync($"Time: {time}")
                           End Function)
        End Sub)

        app.Run(Async Function(context As HttpContext) As Task
                    Await context.Response.WriteAsync("Hello METANIT.COM")
                End Function)

        app.Run()
    End Sub
End Module

В данном случае метод app.UseWhen() в качестве первого параметра получает следующее условие:

Function(context) context.Request.Path.Value = "/time"

Второй параметр определяет действие, в котором создается ответвление конвейера:

Sub(appBuilder)
    'логгируем данные - выводим на консоль приложения
    appBuilder.Use(Async Function(context, nextMiddleware) As Task

        Dim time = Now.ToShortTimeString()
        Console.WriteLine($"Time: {time}")
        Await nextMiddleware() 'вызываем следующий middleware
    End Function)
    'отправляем ответ
    appBuilder.Run(Async Function(context) As Task
        Dim time = Now.ToShortTimeString()
        Await context.Response.WriteAsync($"Time: {time}")
    End Function)
End Sub

В данном действии в конвейер обработки запроса встраиваются два middleware - с помощью методов Use() и Run(). В первом middleware логгируем это время на консоль приложения. Во втором - терминальном компоненте middleware отправляем информацию о времени в ответ клиенту.

Если мы обращаемся к приложению по пути, который отличается от "/time", то условие в методе UseWhen() ложно, поэтому ответвления конвейера не выполняется. И выполняется middleware из метода app.Run():

Ответвление конвейера обработки запроса в ASP.NET Core и Visual Basic .NET

Однако если мы обращаемся по пути "/time", то условие в методе app.UseWhen() будет истинно. Соответственно будет выполняться ответвление конвейера, который будет обрабатывать запрос. В итоге на консоль приложения, а также в браузере будет выводиться текущее время.

Ответвление конвейера обработки запроса в ASP.NET Core и Visual Basic .NET

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

Imports Microsoft.AspNetCore.Builder
Imports Microsoft.AspNetCore.Http
Module Program
    Sub Main(args As String())

        Dim builder = WebApplication.CreateBuilder(args)
        Dim app = builder.Build()

        app.UseWhen(Function(context) context.Request.Path.Value = "/time", ' если путь запроса "/time"
            Sub(appBuilder)
                Dim time = Now.ToShortTimeString()
                'логгируем данные - выводим на консоль приложения
                appBuilder.Use(Async Function(context, nextMiddleware) As Task
                                   Console.WriteLine($"Time: {time}")
                                   Await nextMiddleware() 'вызываем следующий middleware
                               End Function)
                'отправляем ответ
                appBuilder.Run(Async Function(context) As Task
                                   Await context.Response.WriteAsync($"Time: {time}")
                               End Function)
            End Sub)

        app.Run(Async Function(context As HttpContext) As Task
                    Await context.Response.WriteAsync("Hello METANIT.COM")
                End Function)

        app.Run()
    End Sub
End Module

В этом случае время будет устанавливаться один раз - при запуске приложения и создании ветки в конвейер. Соответственно вне зависимости от того, сколько раз мы будем обращаться к приложению по пути "/time", мы будем получать одно и то же время.

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

Imports Microsoft.AspNetCore.Builder
Imports Microsoft.AspNetCore.Http
Module Program
    Sub Main(args As String())

        Dim builder = WebApplication.CreateBuilder(args)
        Dim app = builder.Build()

        app.UseWhen(Function(context) context.Request.Path.Value = "/time", ' если путь запроса "/time"
            Sub(appBuilder)
                'логгируем данные - выводим на консоль приложения
                appBuilder.Use(Async Function(context, nextMiddleware) As Task
                                   Dim time = DateTime.Now.ToShortTimeString()
                                   Console.WriteLine($"Time: {time}")
                                   Await nextMiddleware() 'вызываем следующий middleware
                               End Function)
            End Sub)

        app.Run(Async Function(context As HttpContext) As Task
                    Await context.Response.WriteAsync("Hello METANIT.COM")
                End Function)

        app.Run()
    End Sub
End Module

В данном случае, если запрос идет по пути "/time", сначала срабатывает ветка конвейера с компонентом, который логгирует время на консоль. А затем выполняется компоненте из app.Run(), который отправляет сообщение "Hello METANIT.COM":

Ответвление конвейера обработки запроса с помощью UseWhen в ASP.NET Core и Visual Basic .NET

MapWhen

Метод MapWhen(), как и метод UseWhen(), на основании некоторого условия позволяет создать ответвление конвейера:

MapWhen (predicate As Func(Of HttpContext, Boolean), configuration As Action(Of IApplicationBuilder));

Метод MapWhen() также реализован как метод расширения для типа IApplicationBuilder, принимает те же параметры, что и UseWhen(), и работает во многом аналогичным образом:

Imports Microsoft.AspNetCore.Builder
Imports Microsoft.AspNetCore.Http

Module Program
    Sub Main(args As String())

        Dim builder = WebApplication.CreateBuilder(args)
        Dim app = builder.Build()

        app.MapWhen(Function(context) context.Request.Path.Value = "/time", 'если путь запроса "/time"
            Sub(appBuilder)
                appBuilder.Run(Async Function(context) As Task
                                   Dim time = Now.ToShortTimeString()
                                   Await context.Response.WriteAsync($"Time: {time}")
                               End Function)
            End Sub)

        app.Run(Async Function(context As HttpContext) As Task
                    Await context.Response.WriteAsync("Hello METANIT.COM")
                End Function)

        app.Run()
    End Sub
End Module

Здесь опять же, если запрошен путь "/time", то срабатывает ветка конвейера, созданная методом app.MapWhen(), в которой клиенту отправляется текущее время. Если путь запроса другой, то срабатывается основной поток конвейера, в котором отправляется сообщение "Hello METANIT.COM".

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850