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") } );