РЕДАКТИРОВАТЬ: Хотя этот ответ по-прежнему применяется для веб-API 1, для веб-API 2 я настоятельно рекомендую использовать ответ Даниэля Халана , поскольку это современный уровень для отображения подресурсов ( среди прочих тонкостей).
Некоторые люди не любят использовать {action} в Web API, потому что они верят, что при этом они нарушат "идеологию" REST ... Я утверждаю это. {действие} - это просто конструкция, которая помогает в маршрутизации. Он является внутренним для вашей реализации и не имеет ничего общего с HTTP-глаголом, используемым для доступа к ресурсу .
Если вы наложите на действия ограничения HTTP-глаголов и присвоите им соответствующие имена, вы не нарушите никаких рекомендаций RESTful и в итоге получите более простые и более лаконичные контроллеры вместо множества отдельных контроллеров для каждого подресурса. Помните: действие - это просто механизм маршрутизации, и оно является внутренним для вашей реализации. Если вы боретесь с фреймворком, то что-то не так с фреймворком или вашей реализацией. Просто сопоставьте маршрут с ограничением HTTPMETHOD, и все готово:
routes.MapHttpRoute(
name: "OneLevelNested",
routeTemplate: "api/customers/{customerId}/orders/{orderId}",
constraints: new { httpMethod = new HttpMethodConstraint(new string[] { "GET" }) },
defaults: new { controller = "Customers", action = "GetOrders", orderId = RouteParameter.Optional, }
);
Вы можете обрабатывать их в CustomersController следующим образом:
public class CustomersController
{
// ...
public IEnumerable<Order> GetOrders(long customerId)
{
// returns all orders for customerId!
}
public Order GetOrders(long customerId, long orderId)
{
// return the single order identified by orderId for the customerId supplied
}
// ...
}
Вы также можете направить действие Создать на тот же «ресурс» (заказы):
routes.MapHttpRoute(
name: "OneLevelNested",
routeTemplate: "api/customers/{customerId}/orders",
constraints: new { httpMethod = new HttpMethodConstraint(new string[] { "POST" }) },
defaults: new { controller = "Customers", action = "CreateOrder", }
);
И обработать его соответствующим образом в контроллере клиента:
public class CustomersController
{
// ...
public Order CreateOrder(long customerId)
{
// create and return the order just created (with the new order id)
}
// ...
}
Да, вам все еще нужно создать много маршрутов только потому, что Web API по-прежнему не может маршрутизировать к различным методам в зависимости от пути ... Но я думаю, что лучше декларативно определять маршруты, чем придумывать настраиваемые механизмы диспетчеризации на основе перечислений или других хитростей.
Для потребителя вашего API он будет отлично выглядеть:
GET http://your.api/customers/1/orders
(отображается на GetOrders (long), возвращая все заказы для клиента 1)
GET http://your.api/customers/1/orders/22
(сопоставляется с GetOrders (long, long), возвращая заказ 22 для клиента 1
POST http://your.api/customers/1/orders
(отображается на CreateOrder (long), который создаст заказ и вернет его вызывающей стороне (с только что созданным новым идентификатором)
Но не принимайте мое слово как абсолютную правду. Я все еще экспериментирую с этим, и я думаю, что MS не удалось должным образом обратиться к доступу субресурса.
Я призываю вас попробовать http://www.servicestack.net/ для менее болезненного опыта написания REST API ... Но не поймите меня неправильно, я обожаю Web API и использую его для большинства моих профессиональных проектов, главным образом потому, что легче найти программистов, которые уже «знают» это ... Для моих личных проектов я предпочитаю ServiceStack.