简体   繁体   English

HttpGet属性的路由名称asp.net核心2中基本通用控制器类的名称

[英]Route Name for HttpGet attribute Name for base generic controller class in asp.net core 2

I have a generic controller, which have several derived controller classes. 我有一个通用控制器,它有几个派生的控制器类。 but I cannot figure out how to handle the HttpGet's route name since it require constant. 但我无法弄清楚如何处理HttpGet的路由名称,因为它需要不变。

[HttpGet("{id}", Name ="should not hard coded here for derived class")]
 public virtual async Task<IActionResult> Get(int id)

I need the route name because in my HttpPost function I want to return CreatedAtRoute() which require HttpGet's route name 我需要路由名称,因为在我的HttpPost函数中我想返回需要HttpGet的路由名称的 CreatedAtRoute()

The route name cannot be hard coded because all the derived class need to have a different route name. 路由名称不能进行硬编码,因为所有派生类都需要具有不同的路由名称。

here is the base controller 这是基本控制器

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);
    }
}

Here is the Derived Controller 这是派生控制器

[Route("api/v1/DerivedControllerA")]
public class DerivedControllerA : BaseController<TimeOff, HRContext>
{
    public DerivedControllerA(IGenericRepository<TimeOff, HRContext> repository, ILogger<DerivedControllerA> logger)
        : base(repository, logger)
    {

    }
}  

Any help would be appreciated, Thank you. 任何帮助将不胜感激,谢谢。

I will not argue with NightOwl888 about use of base controllers in MVC. 我不会与NightOwl888争论在MVC中使用基本控制器。 There are pros and cons, and I've dealt with the projects where use of base controllers was justified. 有利有弊,我已经处理过使用基本控制器的项目是合理的。

As regards original question, seems like the easiest way to get around this problem is to use CreatedAtAction instead of CreatedAtRoute . 至于原始问题,似乎解决这个问题的最简单方法是使用CreatedAtAction而不是CreatedAtRoute CreatedAtAction does not require you to name your routes, you could just use Get action name from base controller. CreatedAtAction不要求您为路由命名,您只需使用从基本控制器Get操作名称即可。 If CreatedAtAction is called from DerivedControllerA , it will produce the URL for Get action in DerivedControllerA , and if it's called from DerivedControllerB , it will produce the URL for Get action in DerivedControllerB . 如果CreatedAtAction从所谓DerivedControllerA ,它会产生的URL Get在行动DerivedControllerA ,如果它是从所谓的DerivedControllerB ,它会产生的URL Get在行动DerivedControllerB So seems like shift to CreatedAtAction covers your use case pretty well. 所以转向CreatedAtAction似乎CreatedAtAction涵盖了你的用例。

Here is a sample call to 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);
}

The common mistake is to call overload of CreatedAtAction with 2 parameters. 常见的错误是使用2个参数调用CreatedAtAction重载。 This version takes created object for response body, not the route values, which often results to No route matches the supplied values error. 此版本为响应正文创建了对象,而不是路由值,这通常导致No route matches the supplied values错误No route matches the supplied values If you don't want to return representation of created resource in the response, you could pass null as 3rd parameter: 如果您不想在响应中返回已创建资源的表示,则可以将null作为第三个参数传递:

    return CreatedAtAction(nameof(Get), new
    {
        //  Put actual id here
        id = 123
    }, null);

If for some reason you want to stick with CreatedAtRoute call, the only possible solution that comes to my mind is to have distinct action in each derived class which just calls to base method with the actual logic: 如果出于某种原因你想坚持使用CreatedAtRoute调用,那么我想到的唯一可能的解决方案是在每个派生类中使用不同的操作,它只使用实际逻辑调用base方法:

[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
    }
}

Such solution however devalues use of BaseController in fact. 然而,这样的解决方案实际上使BaseController使用贬值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM