Web Api 核心 2 区分 GET

Web Api Core 2 distinguishing GETs

为什么 Web API Core 2 无法区分这些?

    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    // GET api/values?name=dave
    [HttpGet]
    public string Get(string name)
    {
        return $"name is {name}";
    }

事情是这样的 -

http://localhost:65528/api/valueshttp://localhost:65528/api/values?name=dave 都会导致第一个 Get() 方法执行。

这段代码在 Web 中运行良好 Api 2.

我有 know multiple 方法解决这个问题,但我不知道 为什么 它会发生。

有人可以解释为什么会这样吗?

我不认为你甚至可以在 ASP.NET Core Mvc 2.0 中编译你的代码,因为你有 2 个动作映射到相同的路径 [HttGet] api/values:

AmbiguousActionException: Multiple actions matched.

请记住,ASP.NET Web API 使用 HTTP 谓词作为请求的一部分来确定调用哪个操作。尽管它使用常规路由(您将操作命名为 Get、Post、Put 和 Delete 等),但如果您没有指定路由属性,我强烈建议始终使用路由属性来注释您的控制器和操作。

Api 设计时间

现在轮到你作为开发者来设计路线了。请记住,路由应该是一个 Uri 可以识别资源的

  • 将名称与路线一起用作标识符

    [Route("api/[controller]")]
    public class CustomersController : Controller
    {
        // api/customers
        [HttpGet]
        public IActionResult Get()
        {
           ...
        }
    
        // api/customers/dave
        [HttpGet("{name:alpha}")]     // constraint as a string 
        public IActionResult GetByName(string name)
        {
            ...
        }
    }
    
  • 使用名称作为过滤器,针对资源集合

    [Route("api/[controller]")]
    public class CustomersController : Controller
    {
        // api/customers
        // api/customers?name=dave
        [HttpGet]
        public IActionResult Get(string name)
        {
            ...
        }
    }
    

让你更迷惑

api/customers/dave还是会先执行GetById

[Route("api/[controller]")]
public class CustomersController : Controller
{
    [HttpGet]
    public IActionResult Get()
    {
        ...
    }

    [HttpGet("{name}")]
    public IActionResult GetByName(string name)
    {
        ...
    }

    [HttpGet("{id}")]
    public IActionResult GetById(int id)
    {
        ...
    }
}

GetByNameGetById 这两种方法都是潜在的候选方法,但 MVC 首先选择 GetById 方法,因为 MVC 比较 method/template 名称 {name}{id} 通过不区分大小写的字符串比较,i 出现在 n.

之前

那是你想要约束.

的时候
[Route("api/[controller]")]
public class CustomersController : Controller
{
    [HttpGet]
    public IActionResult Get()
    {
        ...
    }

    // api/customers/dave
    [HttpGet("{name:alpha}")]
    public IActionResult GetByName(string name)
    {
        ...
    }

    // api/customers/3
    [HttpGet("{id:int}")]
    public IActionResult GetById(int id)
    {
        ...
    }
}

您也可以指定 排序

[Route("api/[controller]")]
public class CustomersController : Controller
{
    [HttpGet]
    public IActionResult Get()
    {
        ...
    }

    // api/customers/portland
    [HttpGet("{city:alpha}", Order = 2)]
    public IActionResult GetByCity(string city)
    {
        ...
    }

    // api/customers/dave
    [HttpGet("{name:alpha}", Order = 1)]
    public IActionResult GetByName(string name)
    {
        ...
    }

    // api/customers/3
    [HttpGet("{id:int}")]
    public IActionResult GetById(int id)
    {
        ...
    }
}

如果没有 Order,方法 GetByCity 将比 GetByName 更受青睐,因为 {city} 的字符 c 在 {name} 的字符 n 之前.但是,如果您指定顺序,MVC 将根据 Order.

选择操作

唉post太长了....

因为在您的情况下,路由管道中的最佳匹配是默认的 httpget 属性(获取所有属性的属性)。查询是一个常规字符串,所以如果您不询问您想要从查询中得到什么,最佳匹配仍然是获得所有的那个。

[HttpGet]
public string Get([FromQuery]string name)
{
    return $"name is {name}";
}

[FromQuery] 指向查询字符串中的键 "name" 以获取值。
你应该阅读 Routing in asp.net core