HttpGet属性的路由名称asp.net core 2中基本通用控制器类的名称 [英] Route Name for HttpGet attribute Name for base generic controller class in asp.net core 2

查看:315
本文介绍了HttpGet属性的路由名称asp.net core 2中基本通用控制器类的名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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("{id}", Name ="should not hard coded here for derived class")]
 public virtual async Task<IActionResult> Get(int id)

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

I need the route name because in my HttpPost function I want to return CreatedAtRoute() which require HttpGet's route name

由于所有派生类都必须具有不同的路由名称,因此不能对路由名称进行硬编码.

The route name cannot be hard coded because all the derived class need to have a different route name.

这是基本控制器

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

    }
}  

我们将不胜感激,谢谢.

Any help would be appreciated, Thank you.

推荐答案

我不会与NightOwl888争论在MVC中使用基本控制器.有优点也有缺点,我已经处理了合理使用基本控制器的项目.

I will not argue with NightOwl888 about use of base controllers in MVC. There are pros and cons, and I've dealt with the projects where use of base controllers was justified.

关于原始问题,解决该问题的最简单方法似乎是使用CreatedAtAction而不是CreatedAtRoute. CreatedAtAction不需要您命名路由,您可以只使用基本控制器中的Get操作名称.如果从DerivedControllerA调用CreatedAtAction,它将在DerivedControllerA中生成Get动作的URL,如果从DerivedControllerB调用,它将在DerivedControllerB中生成Get动作的URL.因此,似乎转移到CreatedAtAction可以很好地满足您的用例.

As regards original question, seems like the easiest way to get around this problem is to use CreatedAtAction instead of CreatedAtRoute. CreatedAtAction does not require you to name your routes, you could just use Get action name from base controller. 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. So seems like shift to CreatedAtAction covers your use case pretty well.

这是对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作为第三个参数传递:

The common mistake is to call overload of CreatedAtAction with 2 parameters. This version takes created object for response body, not the route values, which often results to No route matches the supplied values error. If you don't want to return representation of created resource in the response, you could pass null as 3rd parameter:

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

如果出于某种原因您想坚持使用CreatedAtRoute调用,我想到的唯一可能的解决方案是在每个派生类中采取不同的操作,这些派生类仅使用实际逻辑调用基本方法:

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:

[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的使用.

Such solution however devalues use of BaseController in fact.

这篇关于HttpGet属性的路由名称asp.net core 2中基本通用控制器类的名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆