MVC忽略并处理Web API路由

我无法弄清楚为什么MVC而不是Web API正在处理路由。

整个路由配置如下:

configuration.Routes.MapHttpRoute ( name: "AdminControllers.TicketingController", routeTemplate: "api/company/tickets", defaults: new { controller = "Ticketing", id = RouteParameter.Optional, action = "GetTickets" } ); 

API控制器看起来像这样:

 public sealed class TicketingController : ApiController { [HttpGet] public HttpResponseMessage GetTickets() { return ControllerContext.Request.CreateResponse(HttpStatusCode.OK); } } 

我对/api/company/tickets执行HTTP / GET请求,我收到以下错误:

未找到路径“/ api / company / tickets”的控制器或未实现IController。

exception的堆栈跟踪指向ASP.NET MVC(不是Web API): System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType)

AFAIK,当您使用错误的框架(MVC)而不是Web API HttpConfiguration.Routes.MapHttpRoute扩展方法映射路由时会发生这种情况。 在上面找到的示例中,您会发现我正在使用正确的资源在Web API中注册控制器。

我可以确认在应用程序启动期间路由已注册。

问题是ASP.NET MVC管道处理路由,显然,它确实找不到整个路由的控制器。

我在这做错了什么?

注意:它是ASP.NET Web API 1.x,我不能使用Web API 2.0(我很想使用属性路由,是的)。

更新:调用后注册路径的图片.MapHttpRoute(...)

在此处输入图像描述

更新2

信不信由你,但当我将路线配置更改为:

 configuration.Routes.MapHttpRoute( name: "AdminControllers.TicketingController", routeTemplate: "api/company/tickets/{id}", defaults: new { controller = "Ticketing", id = RouteParameter.Optional, action = "GetTickets" } ); 

并且Web API操作更改为:

 [HttpGet] public HttpResponseMessage GetTickets(int? id) { return ControllerContext.Request.CreateResponse(HttpStatusCode.OK); } 

看起来像路由参数使得路由不同以至于被MVC忽略然后由Web API管道处理。 但我可以确认没有其他路线以“api / company /”开头。

无论如何,如果我给id (fe /api/company/tickets/11 ),它就有效。 否则,MVC管道处理路由……

寻找解决方案后,我有一个工作。

首先,我正在向Windows Azure Pack管理员站点(AdminSite)部署Web API控制器。 它是用ASP.NET MVC 4.0制作的。 无论如何,我相信如果你发现我将要在任何ASP.NET MVC和Web API混合应用程序中描述的相同问题,我的答案应该是有意义的。

Windows Azure Pack注册此ASP.NET MVC路由: {controller}/{action}/{id} :问题!

*是的,因为它是一个适合Web API控制器URI方案的URL路由… **

在此处输入图像描述

所以呢?

在一天结束时,解决了在MVC之前放置Web API路由的问题。 这样,ASP.NET会将请求路由到某些URI路由模式的第一个巧合:

 // #1 we add the whole routes. One for listing, other for getting // a single entity (ticket) configuration.Routes.MapHttpRoute( name: "Company.AzurePack.Ticketing.List", routeTemplate: "api/company/tickets", defaults: new { controller = "Ticketing", action = "GetTickets" } ); configuration.Routes.MapHttpRoute( name: "Company.AzurePack.Ticketing.GetOne", routeTemplate: "api/company/tickets/{id}", defaults: new { controller = "Ticketing", action = "GetTicket" } ); // #2 we get both added routes from the route table and we create two // references to them. Later, we remove and re-insert them at the top // of route table. BINGO! RouteBase apiRoute1 = RouteTable.Routes[RouteTable.Routes.Count - 1]; RouteBase apiRoute2 = RouteTable.Routes[RouteTable.Routes.Count - 2]; RouteTable.Routes.Remove(apiRoute1); RouteTable.Routes.Remove(apiRoute2); RouteTable.Routes.Insert(0, apiRoute1); RouteTable.Routes.Insert(0, apiRoute2); 

等等,Web API路由注册到GlobalConfiguration.Configuration.Routes路由表…

是的,但HttpConfiguration.Routes也在RouteTable.Routes注册其路由,ASP.NET管道与RouteTable.Routes 。 也就是说,MVC和WebAPI路由都在同一个路由表中。

在下面的屏幕截图中,您将发现Web API路由的类型为HttpWebRoute

在此处输入图像描述

现在这些URI由花哨的Web API控制器提供服务:

  • / API /公司/票
  • / API /公司/票/ 11

一种让我们的生活更轻松的延伸方法!

在我检查此解决方案正常工作后,我将上面的示例代码重构为扩展方法:

 public static class HttpRouteCollectionExtensions { public static IHttpRoute MapHttpRouteAt(this HttpRouteCollection routes, int index, string name, string routeTemplate, object defaults = null, object constraints = null, HttpMessageHandler handler = null) { Contract.Requires(routes != null); IHttpRoute route = routes.MapHttpRoute(name, routeTemplate, defaults, constraints, handler); RouteBase apiRoute = RouteTable.Routes[RouteTable.Routes.Count - 1]; RouteTable.Routes.Remove(apiRoute); RouteTable.Routes.Insert(index, apiRoute); return route; } } 

…现在我可以在路由表的顶部添加路由,如下所示:

 configuration.Routes.MapHttpRouteAt( index: 0, name: "sampleRoute", routeTemplate: "api/some/path/{name}", defaults: new { controller = "Some", action = "SomeAction", httpMethod = new HttpMethodConstraint("GET") } );