在以下链接的5分钟视频中,以1:10标记,Jon Galloway说,按照惯例,将一个名为DeleteComment的方法添加到他的CommentsController Controller 类中将自动映射到delete http动词。
带有WebApi的MVC如何知道如何将方法路由到正确的动词上?我知道global.asax.cs文件中的路由会将请求路由到正确的 Controller ,但是删除请求如何“按惯例映射”到delete方法或任何方法?尤其是当每个动词可以使用一种以上的方法时? “按惯例”使我认为它只是在查看方法名称中的第一个单词……但是,如果这样,则必须读取方法的签名以区分两个删除方法或两个get方法……以及在哪里所有这些都定义了吗?
视频:
http://www.asp.net/web-api/videos/getting-started/delete-and-update
谢谢!
编辑:
这是WebApi模板随附的示例ValuesController类中的代码。这是我最初提出的问题的根源。区分这些(和 Controller 中的任何其他方法)的“约定”如何工作?
// GET /api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET /api/values/5
public string Get(int id)
{
return value;
}
最佳答案
我先向您道歉,这篇帖子与您的要求有些出入,但当我阅读您的问题时,所有这些都浮出水面。
WebAPI匹配语义
WebAPI使用(默认路由)的匹配语义非常简单。
因此,在您的代码示例中,不带参数的GET请求与不带参数的
Get*( )
函数匹配。获取包含和ID的内容将查找Get***(int id)
。示例
尽管匹配语义很简单,但是它给MVC开发人员(至少是这个开发人员)带来了一些困惑。让我们看一些例子:
奇数名称-您的get方法可以命名为任何名称,只要它以“get”开头即可。因此,在小部件 Controller 的情况下,您可以将函数命名为
GetStrawberry()
,它将仍然匹配。将匹配视为:methodname.StartsWith("Get")
多种匹配方法-如果您有两个没有参数的Get方法会怎样?
GetStrawberry()
和GetOrange()
。尽我所知,在您的代码中首先定义的功能(文件顶部)胜出...奇怪。这样做的副作用是使 Controller 中的某些方法无法访问(至少使用默认路由)....陌生人。NOTE : the beta behaved as above for 'matching multiple methods' - the RC & Release version is a bit more OCD. It throws an error if there are multiple potential matches. This change removes the confusion of multiple ambiguous matches. At the same time, it reduces our ability to mix REST and RPC style interfaces in the same controller, relying on the order & overlapping routes.
怎么办?
好吧,WebAPI是新的,共识仍在凝聚。社区似乎对REST原则颇有兴趣。但是,并非每个API都可以或应该是RESTful的,有些更自然地以RPC样式表示。 REST和人们所说的REST似乎是quite a bit of confusion,well at least to Roy Fielding的来源。
作为一个实用主义者,我怀疑许多API都是RESTful的,其中包含少量的RPC样式方法。首先,仅凭 Controller 的普及(使用webapi绑定(bind)方法)就将 push 开发者疯狂。其次,WebAPI实际上并没有内置的方法来创建api路径的嵌套结构(意思是:
/api/controller/
很简单,但是/api/CATEGORY/Sub-Category/Controller
可行,但是很痛苦)。从我的 Angular 来看,我希望看到webAPI文件夹结构可以控制默认的API路径……这意味着,如果我在UI项目中创建了Category文件夹,则
/api/Category
将是默认路径(parallel to this MVC article)。我该怎么办?
因此,我有一些要求:(1)在大多数情况下能够使用 Restful 语法,(2) Controller 之间有一些“命名空间”分离(请考虑子文件夹),(3)可以调用其他rpc-必要时使用类似方法。实现这些要求归结为巧妙的路由。
// SEE NOTE AT END ABOUT DataToken change from RC to RTM
Route r;
r = routes.MapHttpRoute( name : "Category1",
routeTemplate : "api/Category1/{controller}/{id}",
defaults : new { id = RouteParameter.Optional } );
r.DataTokens["Namespaces"] = new string[] {" UI.Controllers.Category1"};
r = routes.MapHttpRoute( name : "Category2",
routeTemplate : "api/Category2/{controller}/{id}",
defaults : new { id = RouteParameter.Optional } );
r.DataTokens["Namespaces"] = new string[] {" UI.Controllers.Category2"};
routes.MapHttpRoute( name : "ApiAllowingBL",
routeTemplate : "api/{controller}/{action}/{id}",
defaults : new { id = RouteParameter.Optional } );
routes.MapHttpRoute( name : "DefaultApi",
routeTemplate : "api/{controller}/{id}",
defaults : new { id = RouteParameter.Optional } );
Namespace
数据 token ,以限制针对特定路由搜索哪些类。将文件夹添加到UI项目时,这与典型的 namespace 设置非常吻合。 说另一种方式
我的解决方案归结为进一步分离 Controller ,因此
/api/XXXX
不会过于拥挤。Category1
),然后将api Controller 放入该文件夹中。 Widget1
文件夹中的Category1
获得了默认 namespace UI.Category1.Widget1
。 /api/Category1/Widget
)。上面看到的第一个映射是通过将/api/Category1
硬编码到路由中来完成的,然后namespace
token 限制了将搜索匹配 Controller 的类。 NOTE: as of the release
DataTokens
are null by default. I'm not sure if this is a bug, or a feature. So I wrote a little helper method and added to myRouteConfig.cs
file....
r.AddRouteToken("Namespaces", new string[] {"UI.Controllers.Category1"});
private static Route AddRouteToken(this Route r, string key, string[] values) {
//change from RC to RTM ...datatokens is null
if (r.DataTokens == null) {
r.DataTokens = new RouteValueDictionary();
}
r.DataTokens[key] = values;
return r;
}
NOTE 2: even thought this is a WebAPI 1 post, as @Jamie_Ide points out in the comments the above solution doesn't work in WebAPI 2 because
IHttpRoute.DataTokens
has no setter. To get around this you can use a simple extension method like this:
private static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, string[] namespaceTokens)
{
HttpRouteValueDictionary defaultsDictionary = new HttpRouteValueDictionary(defaults);
HttpRouteValueDictionary constraintsDictionary = new HttpRouteValueDictionary(constraints);
IDictionary<string, object> tokens = new Dictionary<string, object>();
tokens.Add("Namespaces", namespaceTokens);
IHttpRoute route = routes.CreateRoute(routeTemplate, defaultsDictionary, constraintsDictionary, dataTokens: tokens, handler:null);
routes.Add(name, route);
return route;
}
关于asp.net-mvc - MVC Web Api中的方法如何映射到http动词?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10439738/