Я извиняюсь заранее, это сообщение немного отходит от того, что вы просили, но все это пузырилось, когда я читал ваш вопрос.
WebAPI Matching Semantic
согласующего семантический, используемый по умолчанию ( маршрутов на в) WebAPI довольно просто.
- Это совпадает с именем действия с глаголом (глагол = GET? Ищет имя методы, начиная с «получить»)
- , если параметр передается, то апи ищет действие с параметром
Таким образом, в вашем примере кода запрос GET без параметра соответствует функции Get*()
без параметров. A Get содержит и ID ищет Get***(int id)
.
Примеры
Хотя соответствующий семантический просто, это создает некоторую путаницу для разработчиков MVC (ну, по крайней мере, этот разработчик). Давайте рассмотрим несколько примеров:
Odd Names - Ваш метод получения может быть назван чем угодно, если он начинается с «get». Поэтому в случае контроллера виджета вы можете назвать свои функции GetStrawberry()
, и он все равно будет соответствовать. Подумайте о совпадении как-то вроде: methodname.StartsWith("Get")
Несколько методов сопоставления - Что произойдет, если у вас есть два метода Get без параметров? GetStrawberry()
и GetOrange()
. Насколько я могу судить, функция, определенная сначала (верхняя часть файла) в вашем коде, выигрывает ... странно. Это имеет побочный эффект, когда некоторые методы в вашем контроллере недоступны (по крайней мере, с маршрутами по умолчанию) ... незнакомец.
ПРИМЕЧАНИЕ: бета вели себя, как описано выше для «совпадающих нескольких методов» - версия Release RC & является немного более OCD. Он выдает ошибку, если имеется несколько потенциальных совпадений. Это изменение устраняет путаницу нескольких неоднозначных совпадений. В то же время, это уменьшает нашу способность смешивать интерфейсы стиля REST и RPC в одном контроллере, опираясь на перекрывающиеся маршруты &.
Что делать?
Ну, WebAPI является новым, и консенсус по-прежнему коалесцирует. Сообщество, похоже, довольно много подходит к принципам REST. Тем не менее, не каждый API может или должен быть RESTful, некоторые более естественно выражены в стиле RPC. REST &, что люди называют REST, как представляется, является источником quite a bitof confusion, wellat least toRoy Fielding.
Как прагматик, я подозреваю, что многие API будут 70% RESTful, с небольшим количеством методов стиля RPC. Во-первых, только распространение контроллера (с учетом метода привязки webapi) будет стимулировать разработчиков bonkers. Во-вторых, WebAPI действительно не имеет встроенного способа создания вложенной структуры путей api (что означает: /api/controller/
легко, но /api/CATEGORY/Sub-Category/Controller
выполнимо, но боль).
С моей точки зрения, я бы хотел, чтобы структура папок webAPI управляла путями API по умолчанию ... что означает, что если я создам папку категории в моем проекте пользовательского интерфейса, тогда /api/Category
будет по умолчанию (что-то parallel to this MVC article).
Что я сделал?
Итак, у меня было несколько требований: (1) иметь возможность использовать успокоительный синтаксис в большинстве случаев, (2) иметь некоторое «пространство имен» для разделения контроллеров (думать о подпапках), (3) иметь возможность звонить дополнительные rpc-подобные методы, когда это необходимо. Реализация этих требований сводилась к умной маршрутизации.
// SEE NOTE AT END ABOUT DataToken change from RC to RTM
Route r;
r = routes.MapHttpRoute(name : "Category1",
routeTemplate : "api/Category1/{controller}/{id}",
defaults : new { id = RouteParameter.Optional });
r.DataTokens["Namespaces"] = new string[] {" UI.Controllers.Category1"};
r = routes.MapHttpRoute(name : "Category2",
routeTemplate : "api/Category2/{controller}/{id}",
defaults : new { id = RouteParameter.Optional });
r.DataTokens["Namespaces"] = new string[] {" UI.Controllers.Category2"};
routes.MapHttpRoute( name : "ApiAllowingBL",
routeTemplate : "api/{controller}/{action}/{id}",
defaults : new { id = RouteParameter.Optional });
routes.MapHttpRoute( name : "DefaultApi",
routeTemplate : "api/{controller}/{id}",
defaults : new { id = RouteParameter.Optional });
- Первые два пути создания "подпапка" маршруты. Мне нужно создать маршрут для каждой подпапки, но я ограничился основными категориями, поэтому я только в итоге получаю 3-10 из них. Обратите внимание, как эти маршруты добавляют токен данных
Namespace
, чтобы ограничить поиск классов по определенному маршруту.Это хорошо соответствует типичной настройке пространства имен, когда вы добавляете папки в проект пользовательского интерфейса.
- Третий маршрут позволяет назвать имена конкретных методов (например, традиционный mvc). Поскольку веб-API удаляет имя действия в URL-адресе, относительно легко определить, какие вызовы требуют этот маршрут.
- Последняя запись маршрута - это веб-маршрут api по умолчанию. Это захватывает любые классы, особенно те, которые находятся вне моих «подпапок».
Упомянутого Другой способ
Мое решение спустилось вниз, чтобы разделяющие контроллеры немного больше так /api/XXXX
не получило слишком многолюдно.
- Я создаю папку в своем проекте пользовательского интерфейса (скажем,
Category1
) и поместил api-контроллеры в папку.
- Visual studio, естественно, устанавливает пространства имен классов на основе папки. Таким образом,
Widget1
в папке Category1
получает пространство имен по умолчанию UI.Category1.Widget1
.
- Естественно, я хотел, чтобы URL-адреса api отображали структуру папок (
/api/Category1/Widget
). Первое сопоставление, которое вы видите выше, обеспечивает, что путем жесткого кодирования /api/Category1
в маршрут, токен namespace
ограничивает классы, которые будут искать соответствующий контроллер.
ПРИМЕЧАНИЕ: от выпуска DataTokens
являются недействительными по умолчанию. Я не уверен, что this is a bug, or a feature. Поэтому я написал небольшой вспомогательный метод и добавил к моему RouteConfig.cs
файл ....
r.AddRouteToken("Namespaces", new string[] {"UI.Controllers.Category1"});
private static Route AddRouteToken(this Route r, string key, string[] values) {
//change from RC to RTM ...datatokens is null
if (r.DataTokens == null) {
r.DataTokens = new RouteValueDictionary();
}
r.DataTokens[key] = values;
return r;
}
Примечание 2: даже думал, что это WebAPI 1 пост, а @Jamie_Ide указывает в комментирует вышеуказанное решение не работает в WebAPI 2, потому что IHttpRoute.DataTokens
не имеет сеттера. Чтобы обойти это, вы можете использовать простой метод расширения, как это:
private static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, string[] namespaceTokens)
{
HttpRouteValueDictionary defaultsDictionary = new HttpRouteValueDictionary(defaults);
HttpRouteValueDictionary constraintsDictionary = new HttpRouteValueDictionary(constraints);
IDictionary<string, object> tokens = new Dictionary<string, object>();
tokens.Add("Namespaces", namespaceTokens);
IHttpRoute route = routes.CreateRoute(routeTemplate, defaultsDictionary, constraintsDictionary, dataTokens: tokens, handler:null);
routes.Add(name, route);
return route;
}
В WebAPI я _think_ вы должны иметь контроллер на ресурс, чтобы вы не имели бы два УДАЛИТЬ методы. –
Спасибо, Шейн, это хорошая информация, но я имею в виду, в частности, как метод одиночной записи и метод с несколькими записями. GET, вероятно, является более подходящим примером, но у вас может быть метод, который получает одну запись по идентификатору, а другой - все записи с определенным FK. Но они оба используют глагол GET; Я не понимаю, где существует разметка маршрутизации, которая различается между ними. –