MVC WebApi 中的方法如何映射到 http 动词?

2023-12-07

在以下链接的 5 分钟视频中,在 1 分 10 秒处,Jon Galloway 表示,将名为 DeleteComment 的方法添加到他的 CommentsController 控制器类中将按照约定自动映射到删除 http 动词。

带有 WebApi 的 MVC 如何知道如何将方法路由到正确的动词?我知道 global.asax.cs 文件中的路由将请求路由到正确的控制器,但是删除请求如何“按约定映射”到删除方法或任何方法?特别是当每个动词可以有超过 1 个方法时? “按照惯例”让我认为它只是查看方法名称中的第一个单词......但如果是这样,它就必须读取方法的签名来区分两个删除方法或两个获取方法......以及在哪里这一切都定义了吗?

Video: http://www.asp.net/web-api/videos/getting-started/delete-and-update

Thanks!

编辑: 以下是 WebApi 模板中的示例 ValuesController 类中的代码。这是我最初问题的来源。区分这些(以及控制器中的任何其他方法)的“约定”如何工作?

// GET /api/values
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    // GET /api/values/5
    public string Get(int id)
    {
        return value;
    }

我提前道歉,这篇文章与您的要求有些偏离,但是当我读到您的问题时,所有这些都浮现出来了。

WebAPI 匹配语义
(thedefault路由)WebAPI 相当简单。

  1. 它将操作名称与动词相匹配(动词 = GET?查找以“get”开头的方法名称)
  2. 如果传递了参数,则 api 会寻找带有参数的操作

因此,在您的代码示例中,不带参数的 GET 请求与Get*( )不带参数的函数。获取包含和 ID 查找Get***(int id).

Examples
虽然匹配语义很简单,但它给 MVC 开发人员(至少是这个开发人员)带来了一些困惑。让我们看一些例子:

奇怪的名字- 你的 get 方法可以命名为任何名称,只要它以“get”开头即可。因此,对于小部件控制器,您可以命名您的函数GetStrawberry()并且仍然会匹配。将匹配视为类似:methodname.StartsWith("Get")

多种匹配方式- 如果您有两个不带参数的 Get 方法,会发生什么情况?GetStrawberry() and GetOrange()。据我所知,代码中首先定义的函数(文件顶部)获胜......奇怪。这会产生副作用,使控制器中的某些方法无法访问(至少对于默认路由)......陌生人。

NOTE:测试版的行为与上面的“匹配多种方法”相同 - RC 和发布版本有点强迫症。如果存在多个潜在匹配项,它会引发错误。此更改消除了多个不明确匹配的混乱。同时,它降低了我们在同一控制器中混合 REST 和 RPC 风格接口的能力,依赖于顺序和重叠路由。

该怎么办?
嗯,WebAPI 是新事物,共识仍在凝聚。社区似乎在很大程度上遵循 REST 原则。然而,并不是每个 API 都可以或应该是 RESTful,有些 API 更自然地以 RPC 风格表达。 REST & 人们所说的 REST 似乎是相当多 混乱的, well 至少到 罗伊·菲尔丁.

作为一个实用主义者,我怀疑许多 API 将是 70% RESTful,带有少量 RPC 风格的方法。首先,仅控制器的激增(考虑到 webapi 绑定方法)就会让开发人员发疯。其次,WebAPI 并没有真正的内置方法来创建 api 路径的嵌套结构(意味着:/api/controller/很容易,但是/api/CATEGORY/Sub-Category/Controller是可行的,但很痛苦)。

从我的角度来看,我希望看到 webAPI 文件夹结构控制默认 API 路径...这意味着如果我在 UI 项目中创建一个类别文件夹,那么/api/Category将是默认路径(与这篇 MVC 文章平行).

我做了什么?
所以,我有一些要求:(1)在大多数情况下能够使用restful语法,(2)控制器有一些“命名空间”分离(认为子文件夹),(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数据令牌,以限制为特定路由搜索哪些类。当您向 UI 项目添加文件夹时,这与典型的命名空间设置非常对应。
  • 第三条路线允许调用特定的方法名称(如传统的 mvc)。由于 Web API 取消了 URL 中的操作名称,因此可以相对容易地判断哪些调用需要此路由。
  • 最后一个路由条目是默认的 Web api 路由。这会捕获任何类,特别是我的“子文件夹”之外的类。

另一种说法
我的解决方案归结为进一步分离控制器/api/XXXX并没有变得太拥挤。

  • 我在我的 UI 项目中创建一个文件夹(可以说Category1),并将 api 控制器放入该文件夹中。
  • Visual Studio 自然地根据文件夹设置类命名空间。所以Widget1 in the Category1文件夹的默认命名空间为UI.Category1.Widget1.
  • 当然,我希望 api URL 能够反映文件夹结构(/api/Category1/Widget)。您在上面看到的第一个映射通过硬编码实现了这一点/api/Category1进入路线,然后namespace令牌限制将搜索匹配控制器的类。

NOTE:截至发布时DataTokens默认为空。我不是 确定如果这是一个错误,或者一个功能。所以我写了一个小助手 方法并添加到我的RouteConfig.cs文件....

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:即使认为这是一篇 WebAPI 1 帖子,正如 @Jamie_Ide 在评论中指出的那样,上述解决方案在 WebAPI 2 中不起作用,因为IHttpRoute.DataTokens没有二传手。为了解决这个问题,你可以使用一个简单的扩展方法,如下所示:

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;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MVC WebApi 中的方法如何映射到 http 动词? 的相关文章

随机推荐

  • IBM Watson - 对话 API 集成返回“未找到资源”错误 (404)

    我正在尝试集成来自 salesforce 的 Watson Http Callout 并收到 404 错误 然后我尝试使用 Postman 工具进行相同的操作 但得到相同的结果 在请求标头中添加了对话凭据 请求端点 https gatewa
  • Python:Selenium xpath 查找具有不区分大小写字符的元素?

    我有能力做到这一点 search View List driver find elements by xpath text normalize space s parent search 但我需要它忽略并将所有元素与文本匹配 例如 VieW
  • iOS Core Plot CPTAxisLabel 与 CTPlot 对齐

    请看下面这张图片 我已附上文件 我的问题是CPTAxisLabel标签 它们被放置在勾号下方 但不被放置在CPTPlot如我所愿 如何向该标签添加左偏移量 我需要将我的标签放置在中间CPTPlot object 更新 void config
  • 如何编写中间带有参数的 PowerShell 别名?

    我正在尝试设置 Windows PowerShell 别名来使用某些参数运行 MinGW 的 g 可执行文件 但是 这些参数需要位于文件名和其他参数之后 我不想经历尝试设置函数之类的麻烦 有没有一种方法可以简单地说 alias mybuil
  • 如何使两种不兼容的类型,但具有相同的成员,可以互换?

    昨天 我们团队中的两个人来找我 提出了一个不常见的问题 我们正在我们的 winforms 应用程序之一中使用第三方组件 所有代码都已经针对它编写了 然后 他们希望将同一供应商提供的另一个第三方组件合并到我们的应用程序中 令他们高兴的是 他们
  • swift tableview如何选择所有行

    我在表格视图中有按钮 我想当我按下该按钮时将选择所有单元格行 该怎么做 我尝试了很多但一无所获 我很困惑如何让按钮接触细胞 我试图让 var 像这样 var x false 那我确实喜欢 if x true Code 当你按下按钮时它就会是
  • 使用 Python 解析文件中的嵌套循环

    目前Python读取文件的每一行并执行一个函数doStep 该函数将传递正在读取的行上的任何内容 data txt a b c b read py fin open data txt for step in fin doStep step
  • Android Wear:收听传入通知

    是否可以在可穿戴 Android 应用程序中监听传入通知 我尝试过实施一个通知监听服务 但是服务的onNotificationPosted 从未被称为 public class MyListenerService extends Notif
  • 如何将应用提交到应用商店?

    我最近制作了我的第一个 iPhone 应用程序 我对 iPhone 编程完全陌生 如何将应用提交到应用商店 因为我是菜鸟 所以我会得到一些详细解释的更好帮助 您可以在中找到详细的解释iOS 开发者计划用户指南
  • 使用 Writer 将 int 写入文本文件

    Writer wr new FileWriter 123 txt wr write 123 wr close 输出文件包含 哪里有问题 怎么写int到文本文件使用Writer 你必须写字符串 你可以试试 wr write 123 OR wr
  • 从 PHP 5.3 开始,mssql_connect 不再工作

    我刚刚收到我们主机的一封电子邮件 他们已将 PHP 升级到 5 3 但不幸的是 所有脚本现在都已损坏 我追踪到了这个函数mssql 连接失败 支持人员告诉我 这在 5 3 中已被弃用 这怎么可能是真的 现在如何在 PHP 5 3 下连接到
  • 如何解决GCC中的包含文件名冲突?

    我有两个名为string h在不同的库中 它们相互冲突 甚至与标准C包含文件的同名冲突 无需使用任何string h除了标准的 但我需要在 GCC 搜索路径中包含库头路径 目前我使用类似的东西 I usr local include lib
  • 如何调试 dsymutil 错误:“Clang 模块预计只有 1 个编译单元。”

    在 iOS 应用程序的GenerateDSYMFile 阶段收到此错误消息 Users name Library Developer Xcode DerivedData ModuleCache HASH FrameworkName HASH
  • EOFException - 如何处理?

    我是一名初学者 Java 程序员 遵循java教程 我正在使用一个简单的 Java 程序Java教程 s 数据流页面 并且在运行时 它不断显示EOFException 我想知道这是否正常 因为读者最终必须到达文件的末尾 import jav
  • HMVC codeigniter 适用于本地服务器,但不适用于 Web 服务器

    这真是要了我的命 我有什么 CI版本 2 1 4 模块化扩展 HMVC 作者 wiredesignz 一个基本的 codeigniter hmvc 项目 可以与 php 5 5 3 的本地服务器 mamp 中的设置配合良好 我的问题 在我将
  • 如何获取默认的 Cargo 输出目录以匹配目标架构?

    我希望构建输出目录遵循我正在构建的架构 目前 当我在没有任何目标的情况下使用 Cargo build 时 它将输出放入 target debug 或 target release 中 当我为其他目标架构构建时 它将它们放入 target a
  • android - 文本输入类型人名不起作用

    在我的 android 项目中 我想要一个类型为 personname 的文本字段 默认情况下大写锁定处于激活状态 但是 此代码不起作用
  • 如何防止 Spring 应用程序上下文关闭,直到关闭钩子被触发

    我有一个弹簧启动应用程序 我已经实施了SmartLifecycle我的 bean 中的接口启动了异步 snmp 服务器start方法并将其停止在其中stop method 一切工作正常 除了主应用程序上下文在启动后立即停止 因此我的服务器
  • Heroku 应用程序数据库重置

    在 Heroku 上运行完 Python 入门后 我启动了我的第一个应用程序 一切似乎都工作正常 但过了一会儿 可能几个小时 数据库会重置 我对根本原因的假设是我的 django 应用程序使用默认的 django 数据库 我认为是 SQLi
  • MVC WebApi 中的方法如何映射到 http 动词?

    在以下链接的 5 分钟视频中 在 1 分 10 秒处 Jon Galloway 表示 将名为 DeleteComment 的方法添加到他的 CommentsController 控制器类中将按照约定自动映射到删除 http 动词 带有 We