Создание специального компонента маршрутизации конечных точек¶
Как уже было сказано, маршрутизация конечных точек разделяет процесс на два этапа, реализуемых отдельными компонентами:
RoutingMiddleware— использует входящий запрос для выбора конечной точки. Предоставляет метаданные о выбранной конечной точке вHttpContext(например, требования к авторизации, задаваемые при помощи[Authorize]);EndpointMiddleware— выполняет выбранную конечную точку для генерации ответа.
Преимущество двухэтапного процесса в том, что можно разместить промежуточное ПО между этапом выбора конечной точки и этапом выполнения.
Пусть мы хотим применить авторизацию к простой конечной точке ping-pong, построенной здесь. Для этого воспользуемся маршрутизацией конечных точек.
Сперва создадим класс PingPongMiddleware (согласно подходу отсюда):
public class PingPongMiddleware
{
public PingPongMiddleware(RequestDelegate next) {}
public async Task Invoke(HttpContext context)
{
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("pong");
}
}
Теперь преобразуем компонент в конечную точку. Для этого создадим мини-конвейер внутри лямбда-функции
UseEndpoints(), используя метод CreateApplicationBuilder():public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
var endpoint = endpoints
.CreateApplicationBuilder()
.UseMiddleware<PingPongMiddleware>()
.Build();
endpoints.Map("/ping", endpoint);
endpoints.MapRazorPages();
endpoints.MapHealthChecks("/healthz");
});
}
Совет
Заметьте, что Map() в IEndpointRouteBuilder создаёт новую конечную точку, ассоциированную с маршрутом. Эта функция концептуально отличается от описанной ранее, которая используется для ветвления конвейера.
Также целесообразно вынести создание конечной точки в отдельный метод расширения:
public static class EndpointRouteBuilderExtensions
{
public static IEndpointConventionBuilder MapPingPong(this IEndpointRouteBuilder endpoints, string route)
{
var pipeline = endpoints
.CreateApplicationBuilder()
.UseMiddleware<PingPongMiddleware>()
.Build();
return endpoints
.Map(route, pipeline)
.WithDisplayName("Ping-pong");
}
}
Теперь метод
UseEndpoints() станет проще:app.UseEndpoints(endpoints =>
{
endpoints.MapPingPong("/ping");
endpoints.MapRazorPages();
endpoints.MapHealthChecks("/healthz");
});
Совет
Здесь мы использовали простой маршрут "/ping", но можно использовать шаблоны маршрута с параметрами, например "/ping/{count}". Подробности см. в блоге автора
Дата создания : 26 октября 2022 г.