【问题标题】:ASP Core 3.1 RoutingASP Core 3.1 路由
【发布时间】:2020-10-13 08:56:43
【问题描述】:

我在单个控制器中有 2 个HttpGet 端点。为了使路线不同,我向其中之一添加了参数。看下一段代码

[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
    [HttpGet("{id:decimal}")]
    public async Task<IActionResult> Get(decimal id)
    {
        var user = await User.GetAsync(id);
        return Ok(user);
    }

    [HttpGet]
    public async Task<IActionResult> GetAll()
    {
        var users = await User.GetAllAsync();
        return Ok(users);
    }
}

问题是第一个端点不可访问。即使我在查询http://localhost:80/api/user?id=1 中有id 参数,我也到达了第二个端点。 期望的行为是

  1. 请求http://localhost:80/api/user?id=1 -> 第一个端点
  2. 请求http://localhost:80/api/user -> 第二个端点

这一定很简单,因为我确信我以前也是这样做的,但现在我卡住了

【问题讨论】:

  • 要到达第一个端点,您需要http://localhost:80/api/user/1。您设置的路由模板期望 id 成为路由的一部分,而不是查询字符串。
  • 是的。鉴于您清楚明确地定义了路由并且您定义的唯一路由将 id 作为 URL 的一部分,您甚至从哪里得到第一个端点的想法?
  • @KirkLarkin Ahaha,真丢脸。谢谢你,先生!都不知道我是怎么犯这样的错误的

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


【解决方案1】:

当你使用

[HttpGet("{id:decimal}")]

这意味着你的网址是这样的

http://localhost:80/api/user/{id}

http://localhost:80/api/user/1

【讨论】:

    【解决方案2】:

    期望的行为是

    1.Request http://localhost:80/api/user?id=1 -> 第一个端点

    2.Request http://localhost:80/api/user -> 第二个端点

    如果您想匹配请求并根据查询字符串将它们映射到预期的操作,您可以尝试实现自定义ActionMethodSelectorAttribute,如下所示。

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    public class QueryStringConstraintAttribute : ActionMethodSelectorAttribute
    {
        public string QueryStingName { get; set; }
        public bool CanPass { get; set; }
        public QueryStringConstraintAttribute(string qname, bool canpass)
        {
            QueryStingName = qname;
            CanPass = canpass;
        }
        public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor action)
        {
            StringValues value;
    
            routeContext.HttpContext.Request.Query.TryGetValue(QueryStingName, out value);
    
            if (QueryStingName == "" && CanPass)
            {
                return true;
            }
            else
            {
                if (CanPass)
                {
                    return !StringValues.IsNullOrEmpty(value);
                }
    
                return StringValues.IsNullOrEmpty(value);
            }
        }
    }
    

    应用于操作

    [HttpGet]
    [QueryStringConstraintAttribute("id",true)]
    [QueryStringConstraintAttribute("", false)]
    public async Task<IActionResult> Get([FromQuery]decimal id)
    {
        //var user = await User.GetAsync(id);
        //return Ok(user);
        
        //for test purpose
        return Ok("ActionWithQueryString");
    }
    
    [HttpGet]
    [QueryStringConstraintAttribute("id", false)]
    [QueryStringConstraintAttribute("", true)]
    public async Task<IActionResult> GetAll()
    {
        //var users = await User.GetAllAsync();
        //return Ok(users);
    
        //for test purpose
        return Ok("ActionWithOutQueryString");
    }
    

    测试结果

    【讨论】:

      猜你喜欢
      • 2021-01-19
      • 2021-01-29
      • 2020-11-15
      • 2021-01-11
      • 1970-01-01
      • 1970-01-01
      • 2020-10-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多