За сопоставление входящих запросов с адресами в приложении отвечает система маршрутизации. На основании результатов сопоставления запроса с адресами в приложении система маршрутизации ASP.NET Core выбирает для обработки запроса определенную конечную точку приложения. Конечная точка или endpoint представляет некоторый код, который обрабатывает запрос. По сути конечная точка объединяет шаблон маршрута, которому должен соответствовать запрос, и обработчик запроса по этому маршруту.
ASP.NET Core по умолчанию предоставляет простой и удобный функционал для создания конечных точек. Ключевым элементом в этом функционале является интерфейс Microsoft.AspNetCore.Routing.IEndpointRouteBuilder. Он определяет ряд методов для добавления конечных точек в приложение. И поскольку класс WebApplication также реализует данный интерфейс, то соответственно все методы интерфейса мы можем вызывать и у объекта WebApplication.
Для использования системы маршрутизации в конвейер обработки запроса добавляются два встроенных компонента middleware:
Microsoft.AspNetCore.Routing.EndpointMiddleware добавляет в конвейер обработки запроса конечные точки. Добавляется в конвейер с помощью метода UseEndpoints()
Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware добавляет в конвейер обработки запроса функциональность сопоставления запросов и маршрутов. Данный middleware выбирает конечную точку, которая соответствует запросу и которая затем обрабатывает запрос. Добавляется в конвейер с помощью метода UseRouting()
Причем обычно не требуется явным образом подключать эти два компонента middleware. Объект WebApplicationBuilder автоматически сконфигурирует конвейер таким образом, что эти два middleware добавляются при использовании конечных точек.
Самым простым способом определения конечной точки в приложении является метод Map, который реализован как метод расширения для типа IEndpointRouteBuilder. Он добавляет конечные точки для обработки запросов типа GET. Данный метод имеет три версии:
Map (pattern As RoutePattern, handler As Delegate) Map (pattern As String, requestDelegate As RequestDelegate) Map (pattern As String, handler As Delegate)
В всех трех реализациях этот метод в качестве параметра pattern
принимает шаблон маршрута, которому должен соответствовать запрос. Данный параметр может представлять тип RoutePattern или string.
Последний параметр представляет действие, которое будет обрабатывать запрос. Это может быть делегат типа RequestDelegate, либо делегат Delegate.
Стоит отметить, что не стоит путать этот метод с одноименным методом Map(), который описан в статье Метод Map и который реализован как метод расширения для типа 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.Map("/", Function(context As HttpContext) "Index Page") app.Map("/about", Function(context As HttpContext) "About Page") app.Map("/contact", Function(context As HttpContext) "Contacts Page") app.Run() End Sub End Module
Здесь определено три конечных точки с помощью трех методов app.Map()
. Первый вызов добавляет конечную точку, которая будет обрабатывать запрос
по пути "/". В качестве обработчика выступает действие
app.Map("/", Function(context As HttpContext) "Index Page")
Результат этого действия - строка "Index Page" - это то, что будет отправляться в ответ клиенту.
Аналогично второй и третий вызовы метода Map добавляют конечные точки для обработки запросов по путям "/about" и "/contact":
Если путь запроса не соответствует ни одной из конечных точек, то приложение отправит ошибку 404:
Выше в примере обрабочики маршрутов возвращали строки, но в принципе это может быть любое значение, например:
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("/user", Function(context As HttpContext) New Person With {.Name = "Tom", .Age = 37}) app.Run() End Sub Class Person Public Property Name As String Public Property Age As Integer End Class End Module
Здесь обработчик запроса второй конечной точки возвращает в ответ объект класса Person. По умолчанию подобные объкты при отправке сериализируются в JSON:
В принципе можно ничего из обработчика не возвращать, посто выполнять некоторые действия:
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("/user", Sub(context As HttpContext) Console.WriteLine("Request Path: /user")) app.Run() End Sub End Module
В данном случае в обработчике второй конечной точки просто логгируем на консоль некоторую информацию.
В примерах выше передаваемый в обработчик параметр context не использовался. Но мы также можем задействовать его для обработки запроса, например:
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", Async Function(context As HttpContext) As Task Await context.Response.WriteAsync("About Page") End Function) app.Run() End Sub End Module
При необходимости обработчик маршрута можно вынести в полноценный метод:
Imports Microsoft.AspNetCore.Builder Imports Microsoft.AspNetCore.Http Module Program Delegate Function RequestHandler(context As HttpContext) As Object Sub Main(args As String()) Dim builder = WebApplication.CreateBuilder(args) Dim app = builder.Build() app.Map("/", New RequestHandler(AddressOf IndexHandler)) app.Map("/user", New RequestHandler(AddressOf UserHandler)) app.Run() End Sub Function IndexHandler(context As HttpContext) Return "Index Page" End Function Function UserHandler(context As HttpContext) Return New Person With {.Name = "Tom", .Age = 37} End Function Class Person Public Property Name As String Public Property Age As Integer End Class End Module
В примере выше для представления обработчиков определен делегат RequestHandler, которые соответствует обработчикам обоих маршрутов по количеству и типу параметров и по типу возвращаемого результата.
Затем в метод app.Map передается объект этого делегата с ссылкой на определенный метод-обработчик запроса.