问题描述
我在 Global.asax 中有默认路由:
I have the default Route in Global.asax:
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
我希望能够针对特定功能,所以我创建了另一条路线:
I wanted to be able to target a specific function, so I created another route:
RouteTable.Routes.MapHttpRoute(
name: "WithActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
所以,在我的控制器中,我有:
So, in my controller, I have:
public string Get(int id)
{
return "object of id id";
}
[HttpGet]
public IEnumerable<string> ByCategoryId(int id)
{
return new string[] { "byCategory1", "byCategory2" };
}
调用 .../api/records/bycategoryid/5
会给我我想要的.但是,调用 .../api/records/1
会给我错误
Calling .../api/records/bycategoryid/5
will give me what I want.
However, calling .../api/records/1
will give me the error
找到多个与请求匹配的操作:...
Multiple actions were found that match the request: ...
我明白为什么会这样 - 路由只是定义了哪些 URL 是有效的,但是当涉及到函数匹配时,Get(int id)
和 ByCategoryId(int id)
匹配 api/{controller}/{id}
,这是混淆框架的地方.
I understand why that is - the routes just define what URLs are valid, but when it comes to function matching, both Get(int id)
and ByCategoryId(int id)
match api/{controller}/{id}
, which is what confuses the framework.
我需要做什么才能让默认 API 路由再次工作,并使用 {action}
保留该路由?我想创建一个名为 RecordByCategoryIdController
的不同控制器来匹配默认 API 路由,为此我会请求 .../api/recordbycategoryid/5
.但是,我发现这是一个肮脏"(因此不令人满意)的解决方案.我一直在寻找这方面的答案,并且没有关于使用带有 {action}
的路线的教程甚至提到这个问题.
What do I need to do to get the default API route to work again, and keep the one with {action}
? I thought of creating a different controller named RecordByCategoryIdController
to match the default API route, for which I would request .../api/recordbycategoryid/5
. However, I find that to be a "dirty" (thus unsatisfactory) solution. I've looked for answers on this and no tutorial out there on using a route with {action}
even mentions this issue.
推荐答案
路由引擎使用与您添加规则相同的顺序.一旦它获得第一个匹配的规则,它将停止检查其他规则并以此来搜索控制器和操作.
The route engine uses the same sequence as you add rules into it. Once it gets the first matched rule, it will stop checking other rules and take this to search for controller and action.
所以,你应该:
将您的具体规则放在一般规则之前(如默认),这意味着使用
RouteTable.Routes.MapHttpRoute
先映射WithActionApi",然后再映射DefaultApi".
Put your specific rules ahead of your general rules(like default), which means use
RouteTable.Routes.MapHttpRoute
to map "WithActionApi" first, then "DefaultApi".
删除 defaults: new { id = System.Web.Http.RouteParameter.Optional }
参数WithActionApi"规则,因为一旦 id 是可选的,url 就像/api/{part1}/{part2}"永远不会进入DefaultApi".
Remove the defaults: new { id = System.Web.Http.RouteParameter.Optional }
parameter of your "WithActionApi" rule because once id is optional, url like "/api/{part1}/{part2}" will never goes into "DefaultApi".
在DefaultApi"中添加一个命名动作,告诉路由引擎输入哪个动作.否则,一旦您的控制器中有多个操作,引擎将不知道要使用哪一个并抛出找到与请求匹配的多个操作:...".然后使其与您的 Get 方法匹配,请使用 ActionNameAttribute.
Add an named action to your "DefaultApi" to tell the route engine which action to enter. Otherwise once you have more than one actions in your controller, the engine won't know which one to use and throws "Multiple actions were found that match the request: ...". Then to make it matches your Get method, use an ActionNameAttribute.
所以你的路线应该是这样的:
So your route should like this:
// Map this rule first
RouteTable.Routes.MapRoute(
"WithActionApi",
"api/{controller}/{action}/{id}"
);
RouteTable.Routes.MapRoute(
"DefaultApi",
"api/{controller}/{id}",
new { action="DefaultAction", id = System.Web.Http.RouteParameter.Optional }
);
还有你的控制器:
[ActionName("DefaultAction")] //Map Action and you can name your method with any text
public string Get(int id)
{
return "object of id id";
}
[HttpGet]
public IEnumerable<string> ByCategoryId(int id)
{
return new string[] { "byCategory1", "byCategory2" };
}
这篇关于Web API 路由 - api/{controller}/{action}/{id} “功能障碍"api/{控制器}/{id}的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!