Конвейер обработки запроса может содержать как конечные точки, так и другие компоненты middleware, которые тоже обрабатывают запрос. Но при сочетании в конвейере конечных точек и других компонентов middleware надо учитывать общий процесс обработки запроса и вызова конечных точек.
Так, если приложение содержит конечные точки, то система маршрутизации на основе процессе URL matching или сопоставления адреса URL с шаблонами маршрута выбирает для обработки определенную конечную точку. Если в приложении есть такая конечная точка, которая соответствует запросу, то компонент middleware Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware устанавливает у объекта HttpContext конечную точку для будущей обработки запроса, которую можно получить с помощью метода HttpContext.GetEndpoint(). Кроме того, устанавливаются значения маршрута, которые можно получить через коллекцию HttpRequest.RouteValues
Однако конечная точка начинает обрабатывать запрос только после того, как все 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.Use(Async Function(context As HttpContext, nextDelegate As RequestDelegate) As Task Console.WriteLine("First middleware starts") Await nextDelegate.Invoke(context) Console.WriteLine("First middleware ends") End Function) app.Map("/", Function(context As HttpContext) As String Console.WriteLine("Index endpoint starts and ends") Return "Index Page" End Function) app.Use(Async Function(context As HttpContext, nextDelegate As RequestDelegate) As Task Console.WriteLine("Second middleware starts") Await nextDelegate.Invoke(context) Console.WriteLine("Second middleware ends") End Function) app.Map("/about", Function(context As HttpContext) As String Console.WriteLine("About endpoint starts and ends") Return "About Page" End Function) app.Run() End Sub End Module
Здесь до и после первой конечной точки с помощью метода app.Use()
в конвейер встроены два middleware. Для получения общей картины
выполнения приложения процесс выполнения логгируется на консоль приложения.
Если мы запустим приложение, то при запросе по адресу "/" ожидаемо для обработки запроса будет выбрана первая конечная точка
Но теперь взглянем на консоль приложения:
Мы видим, что конечная точка выполняется после того, как начнет выполняться компонент 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.Use(Async Function(context As HttpContext, nextDelegate As RequestDelegate) As Task If context.Request.Path.Value = "/date" Then Await context.Response.WriteAsync($"Date: {Now.ToShortDateString()}") Else Await nextDelegate.Invoke(context) End If End Function) app.Map("/", Function(context As HttpContext) "Index Page") app.Map("/about", Function(context As HttpContext) "About Page") app.Run() End Sub End Module
Кроме того, 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.Use(Async Function(context As HttpContext, nextDelegate As RequestDelegate) As Task Await nextDelegate.Invoke(context) 'постдействие If context.Response.StatusCode = 404 Then Await context.Response.WriteAsync("Resource Not Found") End If End Function) app.Map("/", Function(context As HttpContext) "Index Page") app.Map("/about", Function(context As HttpContext) "About Page") app.Run() End Sub End Module
Однако если в конце конвейера располагается терминальный компонент, то он будет выполняться даже если конечная точка соответствует запрошенному пути:
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.Map("/", Function(context As HttpContext) "Index Page") app.Map("/about", Function(context As HttpContext) "About Page") app.Run(Async Function(context As HttpContext) As Task context.Response.StatusCode = 404 Await context.Response.WriteAsync("Resource not found") End Function) app.Run() End Sub End Module
В данном случае по результату программы мы видим, что даже при запросах по адресу "/" и "/about" будет выполняться middleware из метода app.Run:
Почему такое происходит? Опять же потому что, сначала выполняются все middleware в конвейере, и только потом выполняется конечная точка.