Я создаю услугу используя ASP.NET WebApi. Хочет добавить опору для переговоров типа содержимого, основанного на расширении в URI, так что я добавил следующее за кодом инициализации услуги:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Formatters.JsonFormatter.AddUriPathExtensionMapping("json", "application/json");
config.Formatters.XmlFormatter.AddUriPathExtensionMapping("xml", "application/xml");
}
}
Для того, чтобы это функционировало, я нуждаюсь в том, чтобы создать два маршрута для каждого действия драйвера (я использую исключительно enrutamiento основано на признаках):
[Route("item/{id}/details")]
[Route("item/{id}/details.{ext}")]
[HttpGet]
public ItemDetail[] GetItemDetails(int id)
{
return itemsService.GetItemDetails(id);
}
[Route("item/{name}")]
[Route("item/{name}.{ext}")]
[HttpPost]
public int CreateItem(string name)
{
return itemsService.Create(name);
}
Это остается уродливым и способствует тому, чтобы код был без необходимости длиной, так что я исследовал способ добавлять маршрут с расширением, автоматически, когда будут верить в нормальный маршрут. Как результат я разработал персонализированное осуществление IDirectRouteProvider
который я могу использовать, зарегистрировав признаки маршрута:
config.MapHttpAttributeRoutes(new AutomaticExtensionRouteProvider());
Код персонализированного поставщика:
public class AutomaticExtensionRouteProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<RouteEntry> GetActionDirectRoutes(
HttpActionDescriptor actionDescriptor,
IReadOnlyList<IDirectRouteFactory> factories,
IInlineConstraintResolver constraintResolver)
{
var result = base.GetActionDirectRoutes(actionDescriptor, factories, constraintResolver);
var list = new List<RouteEntry>(result);
foreach(var route in result.Where(r => !r.Route.RouteTemplate.EndsWith(".{ext}")))
{
var newTemplate = route.Route.RouteTemplate + ".{ext}";
if (!result.Any(r => r.Route.RouteTemplate == newTemplate))
{
var entry = new RouteEntry(null, new HttpRoute(newTemplate,
new HttpRouteValueDictionary(route.Route.Defaults),
new HttpRouteValueDictionary(route.Route.Constraints),
new HttpRouteValueDictionary(route.Route.DataTokens)));
list.Add(entry);
}
}
return list.AsReadOnly();
}
}
Проблема состоит в том, что это функционирует хорошо, но не удается в случае: Когда последняя часть маршрута - параметр без ограничений. Итак, в предыдущем примере, создании маршрутов для GetItemDetails
функционируй, но для CreateItem
брось следующее:
System.InvalidOperationException: Multiple actions were found that match the request:
CreateItem on type FooBar.Api.Controllers.ItemsController
CreateItem on type FooBar.Api.Controllers.ItemsController
at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)
at System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)
Я представляю себе, откуда может приходить проблема: Произвольная цепь истекает главные файлы {name}
и {name}.{ext}
, а следовательно механизм WebApi запутывается, попробовав выбирать подходящий маршрут. Но тогда: Почему оно функционирует, когда определяются два маршрута ясно в признаках? А следовательно я понимаю, маршрут, в который я верю в классе AutomaticExtensionRouteProvider
она идентична той, которая создается ясно с признаком (и если я отлаживаю, я вижу, что он действительно так).
Итак: Что происходит здесь?
Я нашел решение.
Оказывается, что маршруты считают распределенным числовое распределенное предшествование, которое механизм enrutamiento WebApi использует, чтобы решать, какой маршрут использовать в случае конфликта. У маршрутов, созданных автоматически для того же действия всегда есть отличное предшествование: но у маршрута, который я создавал вручную, было то же предшествование, что и уже существующая!
Итак решение состоит в том, чтобы добавлять следующее в GetActionDirectRoutes
, немедленно после new RouteEntry
:
entry.Route.DataTokens["precedence"] =
((decimal)route.Route.DataTokens["precedence"]) - 0.1M;