Вопрос или проблема
Я использую NSwag для генерации кода контроллера для сервиса c# Open API
Затем, в Program.cs, это просто простой код из демонстрационного проекта
var builder = WebApplication.CreateBuilder(args);
// Добавить сервисы в контейнер.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Настроить конвейер HTTP-запросов.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Я могу запустить и протестировать сервис, что здесь вполне нормально.
Но что я не понимаю, так это то, что я не указываю имя сгенерированного класса контроллера в вызове метода builder.Services.AddControllers() или app.MapControllers().
Как время выполнения знает, какой контроллер ему следует использовать, что/где эта магия?
Это что-то, что выполняется с помощью рефлексии подлежащей платформы? Я имею в виду перебор всех классов и поиск тех, что реализуют интерфейс контроллера?
Если это так, есть ли причина, по которой это спроектировано именно таким образом, это немного сложно для понимания.
Для grpc или размещенной службы нам по крайней мере нужно указать класс (services.AddGrpcClient/services.AddHostedService) для его обработки, но почему не контроллер Open API?
Ответ или решение
Конечно! Позвольте мне объяснить, как в ASP.NET Core добавляются контроллеры Open API и каким образом происходит их автоматическое обнаружение.
При использовании NSwag для генерации кода контроллеров Open API, по умолчанию создаются контроллеры, унаследованные от базового класса ControllerBase
. Когда вы вызываете метод builder.Services.AddControllers()
, вы регистрируете службы, связанные с контроллерами в Dependency Injection (DI) контейнере. Но интересный момент заключается в том, что AddControllers()
указывает ASP.NET Core искать все классы, которые наследуются от ControllerBase
, и именно поэтому вам не нужно явно указывать имена контроллеров.
Как это работает?
-
Отражение (Reflection): Да, на самом деле, ASP.NET Core использует отражение для поиска всех контроллеров в сборке. Когда приложение запускается, фреймворк проходит через все загруженные сборки и ищет классы, которые наследуются от
ControllerBase
и имеют атрибуты, такие как[ApiController]
и[Route]
. Это позволяет автоматически обнаруживать и регистрировать контроллеры в приложении. - Маршрутизация: Когда вы вызываете
app.MapControllers()
, фреймворк также настраивает маршрутизацию на основе атрибутов, находящихся в контроллерах. Если контроллер, например, имеет атрибут[Route("api/[controller]")]
, маршрутизатор сможет определить, как обрабатывать входящие HTTP-запросы и к какому контроллеру их направлять.
Почему это сделано?
Дизайн, позволяющий автоматически обнаруживать контроллеры, значительно упрощает разработку API, делая его более удобным и менее раздражающим для разработчиков. Это означает, что вам не нужно беспокоиться о ручном указании каждого контроллера, что упрощает добавление новых контроллеров в проект.
В отличие от gRPC и других специфических служб, таких как AddGrpcClient
или AddHostedService
, где требуется явно указать класс для регистрации, контроллеры RESTful в ASP.NET Core построены на широкой концепции маршрутизации и использования атрибутов. Они интегрированы в архитектуру фреймворка и могут быть динамически обнаружены, что делает их более естественными и легкими в использовании для сценариев API.
Заключение
Таким образом, автоматическое обнаружение контроллеров в ASP.NET Core — это результат использования отражения и системы маршрутизации, что делает процесс разработки более удобным и эффективным. Если вы хотите углубиться в эту тему, рекомендуется изучить документацию по маршрутизации и DI в ASP.NET Core.
Надеюсь, это поможет вам лучше понять, как работает механика добавления контроллеров Open API в вашем приложении!