asp.net-mvc - MVC Web Api中的方法如何映射到http动词?

标签 asp.net-mvc asp.net-mvc-routing asp.net-web-api

在以下链接的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使用(默认路由)的匹配语义非常简单。

  • 它将 Action 的名称与动词匹配(动词= GET?以“get”开头的方法名称进行查找)
  • 如果传递了参数,则api会使用
  • 参数来寻求 Action

    因此,在您的代码示例中,不带参数的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 confusionwell 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 } );
    
  • 前两个路由创建“子文件夹”路由。我需要为每个子文件夹创建一条路线,但是我将自己限制在主要类别中,因此最终只得到其中的3-10个。请注意,这些路由如何添加Namespace数据 token ,以限制针对特定路由搜索哪些类。将文件夹添加到UI项目时,这与典型的 namespace 设置非常吻合。
  • 第三种途径允许调用特定的方法名称(如传统的mvc)。由于Web API取消了URL中的操作名称,因此比较容易分辨出哪些 call 需要此路由。
  • 最后的路由条目是默认的Web api路由。这可以捕获任何类,尤其是我的“子文件夹”之外的类。

  • 说另一种方式
    我的解决方案归结为进一步分离 Controller ,因此/api/XXXX不会过于拥挤。
  • 我在UI项目中创建一个文件夹(让我们说Category1),然后将api Controller 放入该文件夹中。
  • Visual Studio自然会基于文件夹设置类 namespace 。因此,Widget1文件夹中的Category1获得了默认 namespace UI.Category1.Widget1
  • 当然,我希望api URL能够反射(reflect)文件夹结构(/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 my RouteConfig.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/

    相关文章:

    asp.net - MVC 4 中的级联下拉列表

    css - 链接图标应该呈现为图像还是带有 css 背景图像 url?

    asp.net-mvc - 如何在 ASP.Net MVC 中初始化 Webhook 接收器

    asp.net-mvc-5 - MVC属性路由添加区域查询字符串参数

    c# - 使用具有流畅验证的自定义验证响应

    asp.net-mvc - ASP.NET MVC - WebSecurity 是如何工作的?

    session - 如何从 MVC5 中的自定义 RouteBase 访问 session ?

    asp.net-mvc - 如何强制链接使用特定路由(MVC路由)

    c# - 如何使用VS2012在对象被释放时进行调试?

    Azure 移动服务 vs Azure 应用服务 vs 普通 Web API