Web Api Core 2区分GET

时间:2017-10-10 19:28:27

标签: asp.net-web-api routing asp.net-web-api-routing asp.net-core-2.0

为什么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解决此问题的方法,但我不知道为什么会发生这种情况。

有人可以解释为什么会发生变化吗?

2 个答案:

答案 0 :(得分:1)

我认为您甚至无法在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通过案例比较方法/模板名称{name}{id} - 敏感字符串比较,in之前。

当您想要约束时。

[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选择操作。

感叹帖子太长了......

答案 1 :(得分:0)

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

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

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