Маршрутизация в ASP.NET Core. Конечные точки (endpoints)

В общем случае, маршрутизация в ASP.NET Core — это механизм сопоставления входящих HTTP-запросов с конкретными обработчиками (конечными точками, endpoints) в приложении. Мы уже знаем, что такое компоненты middleware и сервисы. Теперь разберемся с тем, как работает маршрутизация и конечные точки.

Конечные точки

Конечная точка (endpoint)  — это исполняемый кода приложения, обрабатывающий запрос. Конечные точки определяются в приложении и настраиваются при запуске приложения. На первый взгляд, что middleware, что endpoint — одно и тоже. Чтобы разобраться в различиях между двумя этими понятиями, разберемся в механизме маршрутизации.

Для использования системы маршрутизации в конвейер обработки запроса добавляются два встроенных компонента middleware:

  • Microsoft.AspNetCore.Routing.EndpointMiddleware  — добавляет в конвейер обработки запроса конечные точки. Для добавления в конвейер используется метод расширения UseEndpoints()
  • Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware — добавляет в конвейер механизм сопоставления запросов и конечных точек. Данный middleware выбирает конечную точку, которая наилучшим образом соответствует запросу и, затем, обрабатывает запрос. Добавляется в конвейер с помощью метода UseRouting()

В большинстве случаев, нам нет необходимости вызывать эти методы расширения вручную, так как WebApplicationBuilder автоматически конфигурирует конвейер чтобы эти два middleware использовались в приложении.

Ключевым типом в маршрутизации является интерфейс IEndpointRouteBuilder, который определяет ряд методов для добавления конечных точек в приложение. Этот интерфейс реализуется классом WebApplication и, поэтому, все методы интерфейса мы можем вызывать у объекта WebApplication.

Пример маршрутизации

Самый простой пример маршрутизации мы можем увидеть как только создаем пустое приложение ASP.NET Core:

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);
        var app = builder.Build();

        app.MapGet("/", () => "Hello World!");

        app.Run();
    }
}

Здесь с помощью метода MapGet() определена одна конечная точка, которая обрабатывает запрос по пути «/». Если выполняется запрос GET, то пользователю отправляется строка «Hello World!». Таким образом, конечная точка, по сути, это некий объект который объединяет путь (или шаблон пути) и действие, которое необходимо выполнить на данный запрос.

Методы Map[xxxx]

У IEndpointRouteBuilder определен ряд методов, которые начинаются с Map. Не стоит путать их с методом расширения Map у IApplicationBuilder. Методы Map, которые мы будем рассматривать ниже — создают конечные точки, метод расширения у IApplicationBuilder — создает ветку конвейера.

Map

Начнем, с основного метода Map, который имеет ряд перегруженных версий:

IEndpointConventionBuilder Map (this IEndpointRouteBuilder endpoints, RoutePattern pattern, RequestDelegate requestDelegate);
RouteHandlerBuilder Map (this IEndpointRouteBuilder endpoints, RoutePattern pattern, Delegate handler);
IEndpointConventionBuilder Map (this IEndpointRouteBuilder endpoints, string pattern, RequestDelegate requestDelegate);
RouteHandlerBuilder Map (this IEndpointRouteBuilder endpoints, string pattern, Delegate handler);

Все эти версии методов добавляют новую конечную точку в которой сопоставляется шаблон маршрута (pattern), которому должен соответствовать запрос и действие (requestDelegate). При этом, шаблон маршрута представляется в виде RoutePattern или string, а действие, как RequestDelegate или Delegate.

Например, добавим в наше приложение следующие endpoints:

int cnt = 0;

app.Map("/", () => "Index Page");

app.Map("/contacts", async (context) => 
{
    context.Response.ContentType = "text/html";
    await context.Response.WriteAsync("<h1>https://csharp.webdelphi.ru</h1>");
});

app.Map("/counter", () => $"{cnt++}");

Здесь мы определили три конечные точки.

Первая точка обрабатывает запрос по пути «/» — выводит пользователю строку «Index Page». Здесь используется Delegate в качестве обработчика. Результат:

Вторая точка — обрабатывает запрос по пути «/contacts» и в качестве обработчика использует RequestDelegate, благодаря чему мы можем использовать контекст запроса, менять заголовки ответа и т.д. Результат:

Третья точка — обрабатывает запрос по пути «/counter»: наращивает на 1 и значение переменной cnt и выводит её пользователю. Результат после нескольких обновлений страницы в браузере:

Стоит отметить, что метод Map() сопоставляет только путь запроса и не использует при сопоставлении метод, которым этот запрос отправлен (GET, POST и т.д.).

Если путь запроса не соответствует ни одному шаблону, то возвращается код 404.

Методы Map[Get, Post, Put, Delete, Patch]

Когда для обработки запроса нам важен не только путь, но и метод HTTP, то можно использовать различные варианты методов Map[xxxx]. Например, если мы хотим, путь «/» обрабатывался только при запросе методом HTTP GET то мы используем метод расширения MapGet() следующим образом:

app.MapGet("/", () => "Index Page");

Теперь, если запрос будет отправляться любым другим методом кроме GET, то сервер будет отвечать пользователю кодом 405 Method Not Allowed. Аналогичным образом, мы можем ограничить маршруты методами HTTP POST, PUT, DELETE или Patch. Для этого используются соответствующие методы, например:

app.MapPost("/", () => "Index Page");
app.MapPut("/", () => "Index Page");

Метод MapMethods

Если нам необходимо, чтобы конечная точка обрабатывала запрос по заданному пути с использованием ряда HTTP методов, то можно использовать метод MapMethods(), следующим образом:

app.MapMethods("/", new[] { "GET", "POST" }, 
async (context) => 
{
   await context.Response.WriteAsJsonAsync(new { Name = "Tom", Age = 34 });
});

Здесь мы использовали для примера RequestDelegate и, если запрос по пути «/» отправляется методом GET или POST, то пользователю возвращается объект в виде JSON:

Итого

Сегодня мы познакомились с основными моментами маршрутизации в ASP.NET Core. Конечная точка — это объект, содержащий информацию, необходимую для выполнения запроса, который создается при запуске приложения. Компоненты middleware настраивают маршрутизацию и сопоставляют запросы с endpoint и, затем, действие определенное в конечной точке выполняется.

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии