Маршрутизация веб-API с несколькими параметрами
Я пытаюсь выяснить, как выполнить маршрутизацию для следующего контроллера веб-API:
public class MyController : ApiController
{
// POST api/MyController/GetAllRows/userName/tableName
[HttpPost]
public List<MyRows> GetAllRows(string userName, string tableName)
{
...
}
// POST api/MyController/GetRowsOfType/userName/tableName/rowType
[HttpPost]
public List<MyRows> GetRowsOfType(string userName, string tableName, string rowType)
{
...
}
}
На данный момент я использую эту маршрутизацию для URL-адресов:
routes.MapHttpRoute("AllRows", "api/{controller}/{action}/{userName}/{tableName}",
new
{
userName= UrlParameter.Optional,
tableName = UrlParameter.Optional
});
routes.MapHttpRoute("RowsByType", "api/{controller}/{action}/{userName}/{tableName}/{rowType}",
new
{
userName= UrlParameter.Optional,
tableName = UrlParameter.Optional,
rowType= UrlParameter.Optional
});
но на данный момент работает только первый метод (с двумя параметрами). Я нахожусь на правильных строках, или я получил неправильный формат URL или маршрутизацию? Маршрутизация кажется мне черной магией...
Ответы
Ответ 1
Проблема заключается в том, что ваш URL api/MyController/GetRowsOfType/userName/tableName/rowType
всегда будет соответствовать первому маршруту, поэтому вторая никогда не будет достигнута.
Просто исправить, сначала зарегистрируйте маршрут RowsByType
.
Ответ 2
Я видел, что WebApiConfig получает "из-под контроля" с сотнями маршрутов, размещенными в нем.
Вместо этого я лично предпочитаю Маршрутизация атрибутов
Вы вводите его в замешательство с помощью POST и GET
[HttpPost]
public List<MyRows> GetAllRows(string userName, string tableName)
{
...
}
HttpPost И GetAllRows?
Почему бы не сделать это:
[Route("GetAllRows/{user}/{table}")]
public List<MyRows> GetAllRows(string userName, string tableName)
{
...
}
ИЛИ изменить маршрут ( "PostAllRows" и "PostRows" ). Я думаю, что вы действительно выполняете запрос GET, поэтому код, который я показываю, должен работать на вас. Ваш звонок от клиента будет WHATEVER находится в ROUTE, поэтому он НАЙДЕТ METHOD с GetAllRows, но сам метод, это имя МОЖЕТ БЫТЬ все, что вы хотите, до тех пор, пока вызывающий объект соответствует URL-адресу в ROUTE, вы можете добавить GetMyStuff для этого метода, если вы действительно этого хотели.
Update:
Я предпочитаю быть explicit
с типом HTTP methods
И я предпочитаю сопоставлять параметры маршрута параметрам метода
[HttpPost]
[Route("api/lead/{vendorNumber}/{recordLocator}")]
public IHttpActionResult GetLead(string vendorNumber, string recordLocator)
{ .... }
(маршрут lead
не должен совпадать с именем метода GetLead
, но вы захотите сохранить те же имена в параметрах маршрута и параметрах метода, даже если вы можете изменить порядок, например, поставить recordLocator до того, как vendorNumber если маршрут противоположный - я этого не делаю, потому что почему более запутанно смотреть на него).
Bonus:
Теперь вы всегда можете использовать регулярное выражение в маршрутах, например
[Route("api/utilities/{vendorId:int}/{utilityType:regex(^(?i)(Gas)|(Electric)$)}/{accountType:regex(^(?i)(Residential)|(Business)$)}")]
public IHttpActionResult GetUtilityList(int vendorId, string utilityType, string accountType)
{