Подтвердить что ты не робот

Строка запроса не работает при использовании маршрутизации атрибутов

Я использую System.Web.Http.RouteAttribute и System.Web.Http.RoutePrefixAttribute, чтобы включить более чистые URL-адреса для моего приложения Web API 2. Для большинства моих запросов я могу использовать маршрутизацию (например, Controller/param1/param2), или я могу использовать строки запросов (например, Controller?param1=bob&param2=mary).

К сожалению, с одним из моих контроллеров (и только с одним) это не удается. Вот мой контроллер:

[RoutePrefix("1/Names")]
public class NamesController : ApiController
{

    [HttpGet]
    [Route("{name}/{sport}/{drink}")]
    public List<int> Get(string name, string sport, string drink)
    {
        // Code removed...
    }

    [HttpGet]
    [Route("{name}/{drink}")]
    public List<int> Get(string name, string drink)
    {
        // Code removed...
    }
}

Когда я делаю запрос на использование маршрутизации, оба работают нормально. Однако, если я использую строку запроса, она терпит неудачу, сообщая мне, что этот путь не существует.

Я попытался добавить следующее к моей функции WebApiConfig.cs class 'Register(HttpConfiguration config) (до и после маршрута по умолчанию), но ничего не сделал:

config.Routes.MapHttpRoute(
name: "NameRoute",
routeTemplate: "{verId}/Names/{name}/{sport}/{drink}",
defaults: new { name = RouteParameter.Optional, sport = RouteParameter.Optional, drink = RouteParameter.Optional },
constraints: new { verId = @"\d+" });

Поэтому для ясности я хотел бы иметь возможность сделать это:

localhost:12345/1/Names/Ted/rugby/coke
localhost:12345/1/Names/Ted/coke

и

localhost:12345/1/Names?name=Ted&sport=rugby&drink=coke
localhost:12345/1/Names?name=Ted&drink=coke

но, к сожалению, версии строк запроса не работают!: (

Обновление

Я удалил второе действие вообще и теперь пытаюсь использовать только сингулярное действие с дополнительными параметрами. Я изменил свой атрибут маршрута на [Route("{name}/{drink}/{sport?}")], так как Тони предложил сделать спорт нулевым, но теперь это почему-то мешает localhost:12345/1/Names/Ted/coke быть допустимым маршрутом по какой-либо причине. Строки запроса ведут себя так же, как и раньше.

Обновление 2 У меня теперь есть исключительное действие в моем контроллере:

[RoutePrefix("1/Names")]
public class NamesController : ApiController
{

    [HttpGet]
    [Route("{name}/{drink}/{sport?}")]
    public List<int> Get(string name, string drink, string sport = "")
    {
        // Code removed...
    }
}

но все же использование строк запроса не находит подходящего пути, в то время как использование метода маршрутизации делает.

4b9b3361

Ответ 1

После долгих кропотливых действий и Googling, я придумал "исправление". Я не знаю, является ли это идеальной/лучшей практикой/простой старой ошибкой, но она решает мою проблему.

Все, что я сделал, это добавить [Route("")] в дополнение к атрибутам маршрута, которые я уже использовал. Это в основном позволяет маршрутизатору Web API 2 разрешать строки запроса, так как теперь это действительный маршрут.

Пример:

[HttpGet]
[Route("")]
[Route("{name}/{drink}/{sport?}")]
public List<int> Get(string name, string drink, string sport = "")
{
    // Code removed...
}

Это делает действительными как localhost:12345/1/Names/Ted/coke, так и localhost:12345/1/Names?name=Ted&drink=coke.

Ответ 2

У меня возникла одна и та же проблема: "Как включить параметры поиска в строку запроса?", в то время как я пытался создать веб-api для моего текущего проекта. После googling, следующее работает отлично для меня:

Действие контроллера Api:

[HttpGet, Route("search/{categoryid=categoryid}/{ordercode=ordercode}")]

public Task<IHttpActionResult> GetProducts(string categoryId, string orderCode)
{

}

URL-адрес, который я пробовал через почтальона:

http://localhost/PD/search?categoryid=all-products&ordercode=star-1932

http://localhost/PD is my hosted api

Ответ 3

При маршрутизации атрибутов вам необходимо указать значения по умолчанию, чтобы они были необязательными.

[Route("{name}/{sport=Football}/{drink=Coke}")]

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

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

Я просто перечитаю вопрос, и я вижу, что у вас есть 2 Получить глаголы с одним и тем же путем. Я считаю, что это вызовет конфликт, поскольку маршрутизация не будет знать, какой из них использовать, возможно, используя необязательные параметры. Вы также можете указать, что он может быть нулевым и выполнить проверку метода о том, как действовать.

[Route("{name}/{sport?}/{drink?}")]

Затем проверьте переменные в методе, чтобы увидеть, являются ли они нулевыми и обрабатываются по мере необходимости.

Надеюсь, это поможет, некоторые? лол

Если это не возможно, этот сайт будет иметь более подробные сведения о маршрутизации атрибутов.

http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2

Клип с этого сайта:

Дополнительные параметры и значения по умолчанию Вы можете указать, что параметр является необязательным, добавляя знак вопроса к параметру, который является:

[Route("countries/{name?}")]
public Country GetCountry(string name = "USA") { }

В настоящее время по необязательному параметру необходимо указать значение по умолчанию для выбора действия для достижения успеха, но мы можем ограничение. (Пожалуйста, сообщите нам, если это важно.)

Значения по умолчанию могут быть указаны аналогичным образом:

[Route("countries/{name=USA}")]
public Country GetCountry(string name) { }

Необязательный параметр '?' и значения по умолчанию должны появляться после встроенные ограничения в определении параметра.

Ответ 4

Просто боковая нота с моей стороны. Для того, чтобы параметры queryString работали, вам необходимо предоставить значение по умолчанию для параметров вашего метода, чтобы сделать его необязательным. Так же, как и при обычном вызове метода С#.

[RoutePrefix("api/v1/profile")]
public class ProfileController : ApiController
{

   ...

   [HttpGet]
   [Route("{profileUid}")]
   public IHttpActionResult GetProfile(string profileUid, long? someOtherId) 
   {
      // ...
   }

   ...

}

Это позволяет мне вызвать конечную точку следующим образом:

/api/v1/profile/someUid
/api/v1/profile/someUid?someOtherId=123

Ответ 5

Использование Route("search/{categoryid=categoryid}/{ordercode=ordercode}") позволит вам использовать как Querystrings, так и параметры встроенного маршрута, как указано mosharaf hossain. Написание этого ответа, поскольку это должно быть лучшим ответом и лучшим способом. Использование Route("") вызовет проблемы, если у вас есть несколько Gets/Puts/Posts/Deletes.

Ответ 6

Поскольку у вас есть [Route("{name}/{drink}/{sport?}")] как маршрутизация атрибутов, этот код никогда не будет удалён.

config.Routes.MapHttpRoute(
name: "NameRoute",
routeTemplate: "{verId}/Names/{name}/{sport}/{drink}",
defaults: new { name = RouteParameter.Optional, sport = RouteParameter.Optional, drink = RouteParameter.Optional },
constraints: new { verId = @"\d+" });

Таким образом, здесь будет выполняться только маршрут атрибута [Route("{name}/{drink}/{sport?}")]. Поскольку ваш запрос localhost:12345/1/Names?name=Ted&sport=rugby&drink=coke, не имеет имени, спорта или напитка в URL-адресе, он не будет соответствовать этому маршруту атрибутов. Мы не рассматриваем параметры строки запроса при сопоставлении маршрутов.

Чтобы решить эту проблему, вам нужно сделать все 3 необязательных в вашем маршруте атрибутов. Затем он будет соответствовать запросу.

Ответ 7

Здесь немного отклонился от ответа @bhargav kishore mummadireddy, но это важное отклонение. Его ответ будет по умолчанию для значений querystring действительным непустым значением. Этот ответ по умолчанию будет опущен.

Он позволяет вам вызывать контроллер через маршрутизацию маршрута или использовать запрос. По сути, он задает значение по умолчанию для строки запроса, что означает, что она всегда будет маршрутизироваться.

Это было важно для меня, потому что я хочу вернуть 400 (Bad Request), если запрос не указан, вместо того, чтобы вернуть ASP.NET ошибку "не удалось найти этот метод на этом контроллере".

[RoutePrefix("api/AppUsageReporting")]
public class AppUsageReportingController : ApiController
    {
        [HttpGet]
        // Specify default routing parameters if the parameters aren't specified
        [Route("UsageAggregationDaily/{userId=}/{startDate=}/{endDate=}")]
        public async Task<HttpResponseMessage> UsageAggregationDaily(string userId, DateTime? startDate, DateTime? endDate)
        {
            if (String.IsNullOrEmpty(userId))
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest, $"{nameof(userId)} was not specified.");
            }

            if (!startDate.HasValue)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest, $"{nameof(startDate)} was not specified.");
            }

            if (!endDate.HasValue)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest, $"{nameof(endDate)} was not specified.");
            }
        }
    }

Ответ 8

Я использую атрибут FromUri в качестве решения

[Route("UsageAggregationDaily")]
public async Task<HttpResponseMessage> UsageAggregationDaily([FromUri] string userId = null, [FromUri] DateTime? startDate = null, [FromUri] DateTime? endDate = null)