Web Api Core 2, отличающие GET

Почему 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/values, и http://localhost:65528/api/values?name=dave вызывают выполнение первого Get() метода.

Этот точный код отлично работает в Web Api 2.

Я знаю несколько способов получить вокруг этого, но я не знаю, почему это происходит.

Может кто-нибудь объяснить, почему это изменилось?


person Bryan    schedule 10.10.2017    source источник
comment
Я не думаю, что строки запроса используются для маршрутов.   -  person    schedule 10.10.2017
comment
Можете ли вы подробнее рассказать об этом?   -  person Bryan    schedule 10.10.2017


Ответы (2)


Я не думаю, что вы даже можете скомпилировать свой код в 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)
    {
        ...
    }
}

Оба метода GetByName и GetById являются потенциальными кандидатами, но MVC сначала выбирает метод GetById, потому что MVC сравнивает имя метода / шаблона {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, потому что символ c из {city} стоит перед символом n из {name}. Но если вы укажете порядок, MVC выберет действие на основе Order.

Вздох, пост слишком длинный ....

person David Liang    schedule 10.10.2017
comment
Для записи, одной из уловок маршрутизации атрибутов является тот факт, что порядок маршрутизации является важным фактором проектирования, а порядок атрибутов .NET по умолчанию не определен. Это означает, что вы всегда должны знать, что если у вас есть похожие маршруты, их необходимо упорядочить (или ограничить). Маршрутизация на основе соглашений обычно требует меньше настроек, является более расширяемой и мощной, а определение порядка так же просто, как их объявление в правильном порядке. - person NightOwl888; 11.10.2017
comment
Спасибо, Дэвид, очень полезно - person Bryan; 11.10.2017

Потому что в вашем случае лучшим совпадением в конвейере маршрута является атрибут httpget по умолчанию (тот, который получает все). Запрос представляет собой обычную строку, поэтому, если вы не спрашиваете, что вы хотите от запроса, лучшим совпадением будет тот, который получит все.

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

[FromQuery] указывает на ключ «name» в строке запроса, чтобы получить значение.
Вы должны прочитать Маршрутизация в ядре asp.net

person Sinan    schedule 10.10.2017