Автоматически Регистрируем Конечные Точки в Минимальных API
В минимальных API регистрация каждой конечной точки через app.MapGet, app.MapPost и т.п. может привести к появлению повторяющегося кода. По мере роста проекта этот ручной процесс становится всё более трудоёмким и загромождать файл Program.cs. Можно попробовать группировать конечные точки, используя методы расширения, но это похоже на переизобретение контроллеров.
Автоматическая регистрация минимальных API значительно упрощает разработку, делая кодовую базу более лаконичной и улучшает удобство сопровождения за счёт создания централизованного механизма регистрации.
Сначала создадим интерфейс. Метод MapEndpoint принимает IEndpointRouteBuilder, который мы сможем использовать для вызова MapGet, MapPost и т.п.
public interface IEndpoint
{
void MapEndpoint(IEndpointRouteBuilder app);
}
Каждая реализация IEndpoint должна содержать ровно одно определение конечной точки. Ничто не мешает регистрировать несколько, но лучше не стоит.
public class GetUserStats : IEndpoint
{
public void MapEndpoint(IEndpointRouteBuilder app)
{
app.MapGet(
"users/{id}/stats",
async (Guid id) =>
{
return await GetStats(id);
}
);
}
}
Теперь используем рефлексию для сканирования сборок .NET и поиска классов, реализующих IEndpoint:
public static IServiceCollection AddEndpoints(
this IServiceCollection services,
Assembly assembly)
{
var svcs = assembly.DefinedTypes
.Where(t => t is
{ IsAbstract: false, IsInterface: false } &&
t.IsAssignableTo(typeof(IEndpoint)))
.Select(t =>
ServiceDescriptor.Transient(typeof(IEndpoint), t))
.ToArray();
services.TryAddEnumerable(svcs);
return services;
}
Наконец создадим метод расширения для регистрации конечных точек. Мы ищем все регистрации IEndpoint. Это будут классы конечных точек, которые мы теперь можем зарегистрировать в приложении, вызвав их метод MapEndpoint. Здесь мы также добавим параметр RouteGroupBuilder для возможности группировки конечных точек.
public static IApplicationBuilder MapEndpoints(
this WebApplication app,
RouteGroupBuilder? rgb = null)
{
var endpoints = app.Services
.GetRequiredService<IEnumerable<IEndpoint>>();
// Регистрируем в группу, если она задана.
// Если нет, то на уровне приложения
var builder = rgb is null ? app : rgb;
foreach (IEndpoint ep in endpoints)
ep.MapEndpoint(builder);
return app;
}
Вот как будет выглядеть файл Program.cs:
- AddEndpoints регистрирует реализации IEndpoint,
- MapEndpoints регистрирует конечные точки.
var builder =
WebApplication.CreateBuilder(args);
…
builder.Services.AddEndpoints(
typeof(Program).Assembly);
var app = builder.Build();
…
app.MapEndpoints();
app.Run();
Итого
Автоматическая регистрация конечных точек в минимальных API может значительно повысить эффективность разработки и удобство сопровождения проекта. Хотя важно признать потенциальное влияние рефлексии на производительность при запуске приложения, а также на возможность использовать Native AOT. Потенциальным улучшением может стать использование генераторов кода для логики регистрации.
Полный код проекта тут.
Источник: https://www.milanjovanovic.tech/blog/automatically-register-minimal-apis-in-aspnetcore