【问题标题】:Route Name for HttpGet attribute Name for base generic controller class in asp.net core 2HttpGet 属性的路由名称 asp.net core 2 中基本通用控制器类的名称
【发布时间】:2018-07-15 23:31:37
【问题描述】:

我有一个通用控制器,它有几个派生的控制器类。但我不知道如何处理 HttpGet 的 路由名称,因为它需要常量。

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

我需要路由名称,因为在我的 HttpPost 函数中,我想返回需要 HttpGet 的 路由名称

的 CreatedAtRoute()

路由名称不能硬编码,因为所有派生类都需要有不同的路由名称。

这是基本控制器

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)
    {

    }
}  

任何帮助将不胜感激,谢谢。

【问题讨论】:

标签: c# asp.net-core-mvc asp.net-core-webapi asp.net-core-routing


【解决方案1】:

我不会与 NightOwl888 争论在 MVC 中使用基本控制器。有利也有弊,我已经处理过使用基本控制器是合理的项目。

关于原始问题,似乎解决此问题的最简单方法是使用CreatedAtAction 而不是CreatedAtRouteCreatedAtAction 不需要您命名您的路线,您可以使用基本控制器中的 Get 操作名称。如果从DerivedControllerA 调用CreatedAtAction,它将在DerivedControllerA 中生成Get 操作的URL,如果从DerivedControllerB 调用它,它将在DerivedControllerB 中生成Get 操作的URL。所以似乎转向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);
}

常见的错误是使用 2 个参数调用 CreatedAtAction 的重载。此版本将创建对象作为响应主体,而不是路由值,这通常会导致 No route matches the supplied values 错误。如果您不想在响应中返回已创建资源的表示,您可以将null 作为第三个参数传递:

    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 的使用。

【讨论】:

  • CreatedAtAction() 做到了。谢谢!
猜你喜欢
  • 2013-05-19
  • 1970-01-01
  • 1970-01-01
  • 2018-09-16
  • 2015-10-25
  • 1970-01-01
  • 2020-01-04
  • 2017-07-10
  • 1970-01-01
相关资源
最近更新 更多