問題描述
我在 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}的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!