路由:解决带查询参数的不明确请求

Routing: Solve ambigous requests with query parameters

鉴于下面的 RecordsController,以下请求应该是可能的并相应地映射到端点

  1. /api/Records
  2. /api/Records/9b858599-7639-45da-acd6-a1323fb019b5
  3. /api/Records/9b858599-7639-45da-acd6-a1323fb019b5?asOf=2022-01-01
  4. /api/Records/9b858599-7639-45da-acd6-a1323fb019b5?From=2022-01-01&To=2022-03-01

映射到:

  1. GetAll(Guid id)
  2. 获取(Guid id)
  3. GetAsOf(Guid id1, [FromQuery] string asOf)
  4. GetHistory(Guid id2,[FromQuery] 字符串来自,[FromQuery] 字符串至)
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;

namespace WebApplication1.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class RecordsController : ControllerBase
    {
        private readonly ILogger<RecordsController> _logger;

        public RecordsController(ILogger<RecordsController> logger)
        {
            _logger = logger;
        }

        [HttpGet()]
        public ActionResult<IEnumerable<Record>> GetAll()
        {
            _logger.LogInformation("GetAll() was used");
            return Ok();
        }

        [HttpGet("{id:Guid}")]
        public ActionResult<Record> Get(Guid id)
        {
            _logger.LogInformation("Get() was used");
            return Ok();
        }

        [HttpGet("{id1:Guid}")]
        public ActionResult<IEnumerable<Record>> GetAsOf(Guid id1, [FromQuery] string asOf)
        {
            _logger.LogInformation("GetAsOf() was used");
            return Ok();
        }
        [HttpGet("{id2:Guid}")]
        public ActionResult<IEnumerable<Record>> GetHistory(Guid id2, [FromQuery] string from, [FromQuery] string to)
        {
            _logger.LogInformation("GetHistory() was used");
            return Ok();
        }
    }

    public class Record
    {
        public Guid Id { get; set; }
        public string Comment { get; set; } = string.Empty;
    }
}

这没有按预期工作。 上述实现会导致 AmbiguousMatchException。

使用 IRouteTemplateProvider.Order 有可能影响此行为,但随后请求 2. - 4. 被路由到具有最低顺序的端点。

除了将 FromQuery 更改为 FromRoute 之外,您是否看到任何可能性?

谢谢!

方法 2-4 确实不明确,因为它们都是相同的端点,只是具有不同的查询参数。因此,您要么需要使它们具有不同的路由,要么可以将端点表示为具有所有可能查询参数的单个方法,然后从那里使用存在的查询参数映射到特定方法。

HttpGet("{id:Guid}")]
public ActionResult<Record> Get(Guid id, [FromQuery] string asOf, [FromQuery] string from, [FromQuery] string to)
{
    if (asOf != null) return GetAsOf(id, asOf);
    if (from != null && to != null) return GetHistory(id, from, to);
    return Get(id);
}

public ActionResult<Record> Get(Guid id)
{
    _logger.LogInformation("Get() was used");
    return Ok();
}

public ActionResult<IEnumerable<Record>> GetAsOf(Guid id, string asOf)
{
    _logger.LogInformation("GetAsOf() was used");
    return Ok();
}

public ActionResult<IEnumerable<Record>> GetHistory(Guid id2, [FromQuery] string from, [FromQuery] string to)
{
    _logger.LogInformation("GetHistory() was used");
    return Ok();
}