Строка запроса не работает при использовании атрибута маршрутизации
Я использую System.Web.Http.RouteAttribute
а также System.Web.Http.RoutePrefixAttribute
включить чистые URL для моего приложения Web API 2. Для большинства моих запросов я могу использовать маршрутизацию (например, Controller/param1/param2
) или я могу использовать строки запроса (например, Controller?param1=bob¶m2=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
учебный класс' 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...
}
}
но, тем не менее, использование строк запроса не находит подходящий путь, в то время как использование метода маршрутизации делает.
8 ответов
После долгих кропотливых трюков и поисков в Google я придумал "починку". Я не знаю, является ли это идеальной / лучшей практикой / просто старой ошибкой, но это решает мою проблему.
Все, что я сделал, это добавил [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
действительный.
Я столкнулся с той же проблемой "Как включить параметры поиска в строку запроса?", Когда пытался создать веб-API для моего текущего проекта. После поиска в Google, у меня работает нормально:
Действие контроллера 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
При маршрутизации атрибутов необходимо указать значения по умолчанию, чтобы они были необязательными.
[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) { }
Необязательный параметр '?' и значения по умолчанию должны появляться после встроенных ограничений в определении параметра.
Еще одно замечание с моей стороны. Чтобы параметры queryString работали, вам нужно предоставить значение по умолчанию для параметров вашего метода, чтобы сделать его необязательным. Точно так же, как и при обычном вызове метода C#.
[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
Вот небольшой отклонение от ответа @bhargav kishore mummadireddy, но важное отклонение. Его ответ по умолчанию установит в качестве значения строки запроса фактическое непустое значение. Этот ответ по умолчанию будет пустым.
Это позволяет вам вызывать контроллер через маршрутизацию пути или используя строку запроса. По сути, он устанавливает значение по умолчанию строки запроса как пустое, то есть оно всегда будет маршрутизироваться.
Это было важно для меня, потому что я хочу вернуть 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.");
}
}
}
С помощью Route("search/{categoryid=categoryid}/{ordercode=ordercode}")
позволит вам использовать как Querystrings, так и параметры встроенного маршрута, как отвечает mosharaf hossain. Написание этого ответа, так как это должно быть лучшим ответом и лучшим способом. С помощью Route("")
вызовет проблемы, если у вас есть несколько Gets/Puts/Posts/Deletes.
Я использую атрибут FromUri в качестве решения
[Route("UsageAggregationDaily")]
public async Task<HttpResponseMessage> UsageAggregationDaily([FromUri] string userId = null, [FromUri] DateTime? startDate = null, [FromUri] DateTime? endDate = null)
Так как у вас есть [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 необязательными в вашем атрибуте route. Тогда это будет соответствовать запросу.