Имя маршрута для HttpGet имя атрибута для базового универсального класса контроллера в asp.net ядро 2
у меня есть общий контроллер, который имеет несколько производных классов контроллера. но я не могу понять, как обрабатывать HttpGet имя по маршруту так как это требует постоянной.
[HttpGet("{id}", Name ="should not hard coded here for derived class")]
public virtual async Task<IActionResult> Get(int id)
мне нужно имя маршрута, потому что в моей функции HttpPost я хочу вернуть CreatedAtRoute (), которые требуют HttpGet имя по маршруту
имя маршрута не может быть жестко закодировано, потому что весь производный класс должен иметь другое название маршрута.
вот базовый контроллер
public abstract class BaseController<TEntity, TContext> : Controller where TEntity : BaseOptionType, new() where TContext : DbContext
{
private readonly IGenericRepository<TEntity, TContext> _repository;
private readonly ILogger<BaseGenericOptionTypesController<TEntity, TContext>> _logger;
public BaseController(IGenericRepository<TEntity, TContext> repository, ILogger<BaseController<TEntity, TContext>> logger)
{
_repository = repository;
_logger = logger;
}
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[HttpGet("{id}", Name = "should not hard code here for derived class")]
public virtual async Task<IActionResult> Get(int id)
{
var optionType = await _repository.FindByIdAsync(id);
if (optionType == null)
{
_logger.LogInformation($"[ID not found]");
return NotFound();
}
return Ok(optionType);
}
}
вот производный контроллер
[Route("api/v1/DerivedControllerA")]
public class DerivedControllerA : BaseController<TimeOff, HRContext>
{
public DerivedControllerA(IGenericRepository<TimeOff, HRContext> repository, ILogger<DerivedControllerA> logger)
: base(repository, logger)
{
}
}
любая помощь будет оценили, спасибо.
1 ответов
я не буду спорить с NightOwl888 об использовании базовых контроллеров в MVC. Есть плюсы и минусы, и я имел дело с проектами, где использование базовых контроллеров был оправдан.
что касается оригинального вопроса, кажется, самый простой способ обойти эту проблему-использовать CreatedAtAction
вместо CreatedAtRoute
. CreatedAtAction
не требует, чтобы вы называли свои маршруты, вы могли бы просто использовать Get
имя действия от базового контроллера. Если CreatedAtAction
вызывается из DerivedControllerA
, оно произведет URL-адрес Get
действий DerivedControllerA
, и если он вызван из DerivedControllerB
, он будет производить URL-адрес Get
действий DerivedControllerB
. Так что, похоже, shift на CreatedAtAction
охватывает ваш случай использования довольно хорошо.
вот пример вызова CreatedAtAction
:
[HttpPost]
public virtual IActionResult Post(/* ... */)
{
// Create and save an instance in repository
// var createdObject = ...;
return CreatedAtAction(nameof(Get), new
{
// Put actual id here
id = 123
}, createdObject);
}
общей ошибкой является вызов перегрузки CreatedAtAction
С 2 параметрами. Эта версия принимает созданный объект для тела ответа, а не значения маршрута, что часто приводит к No route matches the supplied values
ошибка. Если не хочешь возвращаться представление созданного ресурса в ответе, вы можете передать null
как 3-й параметр:
return CreatedAtAction(nameof(Get), new
{
// Put actual id here
id = 123
}, null);
если по какой-то причине вы хотите придерживаться с CreatedAtRoute
вызов, единственное возможное решение, которое приходит мне на ум, - это иметь отдельное действие в каждом производном классе, который просто вызывает базовый метод с фактической логикой:
[Route("api/v1/DerivedControllerA")]
public class DerivedControllerA : BaseController<TimeOff, HRContext>
{
// ...
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[HttpGet("{id}", Name = "RouteForDerivedControllerA")]
public virtual Task<IActionResult> Get(int id)
{
return base.Get(id);
}
}
public abstract class BaseController<TEntity, TContext> : Controller where TEntity : BaseOptionType, new() where TContext : DbContext
{
// ...
public virtual async Task<IActionResult> Get(int id)
{
// Actual logic goes here
}
}
такое решение однако обесценивает использование BaseController
в самом деле.