Метод 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()
:
Однако если мы обращаемся по пути "/time", то условие в методе app.UseWhen()
будет истинно. Соответственно будет выполняться ответвление конвейера, который будет обрабатывать запрос.
В итоге на консоль приложения, а также в браузере будет выводиться текущее время.
Стоит отметить, что создание ветки происходит один раз при запуске приложения. Например, в примере выше мы видим, что получение времени производится в обоих 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":
Метод 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".