我有一个使用基于约定的路由的Asp.net MVC Web应用程序。我最近添加了一些Web Api 2控制器,我使用了属性路由。尽管文档声称您可以同时使用这两种方法,但我可以使用(属性路由)API方法,或者(常规路由)Web应用程序方法。
这是RouteConfig.RegisterRoutes():
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Tables", action = "Index", id = UrlParameter.Optional },
namespaces: new string[] { "Foo.Cms.Controllers" }
);
}
这是WebApiConfig.Register():
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
// Uncomment the following line of code to enable query support for actions with an IQueryable or IQueryable<T> return type.
// To avoid processing unexpected or malicious queries, use the validation settings on QueryableAttribute to validate incoming queries.
// For more information, visit http://go.microsoft.com/fwlink/?LinkId=279712.
//config.EnableQuerySupport();
// The models currently only serialize succesfully to xml, so we'll remove the json formatter.
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.JsonFormatter);
}
这是Application_Start():
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
}
这样,只有到web api控制器的路由才有效。如果我切换GlobalConfiguration.Register()和RouteConfig.RegisterRoutes(),如下所示:
RouteConfig.RegisterRoutes(RouteTable.Routes);
GlobalConfiguration.Configure(WebApiConfig.Register);
...只有基于会议的路由才有效。
我很茫然。这是怎么回事?
编辑:
我想要实现的目标:
应用程序当前使用基本{controller} / {action} / parameters约定。所以我有一个名为ElementsController的控制器,例如,它有一个路由到/ Elements的Index()方法或一个路由到/ Elements / ListPublic的ListPublic()方法。我通过上面提到的基于约定的路由实现了这一点。
我还有一堆Web Api控制器(例如,TablesController),我想使用/ api / v0 / tables路由路由到它。我试图这样做:
[RoutePrefix("api/v0/tables")]
public class TablesController : ApiController
{
[Route()]
public string Get()
{
// ...
}
}
正如您所看到的,它不是相同的路由模式:api调用都以api / v0 /为前缀。但出于某种原因,它似乎仍将其视为默认的{controller} / {action}路由。
答案 0 :(得分:1)
发生的事情是&#34;首次注册&#34;路线正在生效。如果我将MVC路由定义为
{controller}/{action}/{id}
和定义为
的Web API路由 {controller}/{action}/{id}
第一条注册路线将生效。
为什么会这样?想象一下,您向服务器发送请求
foo/bar/1
这匹配哪条路线?
两个!
无论使用何种路由,它都会选择与路径匹配的第一个结果。如果您想了解如何使这些路线有效的示例,请查看此link
答案 1 :(得分:0)
如果URL匹配两个不同的路由模板,如果它们引用MVC或Web API并不重要,唯一的规则是第一个注册的路由将用于选择要执行的操作。
在特定情况下,如果您对此URL发出GET请求:/api/v0/tables
,则操作选择器会开始检查已注册的路由。
您注册的第一条路线是MVC路线,如下所示:/{controller}/{action}/{id}
。因此,模板与此值匹配:
controller = "api"
action = "v0"
id = "tables"
如果在MVC路由之前注册属性路由,则第一个匹配的路由模板将是您的路由属性模板,因此将正确选择Web API控制器操作。
换句话说,如果您需要在同一个应用程序中路由Web API和MVC,则必须使用与每个操作匹配不同URL的路由,并注意它们的注册顺序:首先注册更具体的模板,然后是更通用的模板,这样通用模板就不会吞下应该与特定模板匹配的URI。
这不是唯一的选择。您还可以使用路径约束,例如,如果您的所有API都具有可以使用约束检查的特定命名约定(例如Regex约束),您仍然可以使用Web API的约定路由。
注意:除了路由匹配之外,操作还支持HTTP方法(如POST,GET等)。因此,您可以在接受不同方法的相同路径中执行两个类似的操作,并且Action选择器将知道选择哪个,但这不能解决您的问题