背景

  问题的起因是这样的。群里面一个哥们儿发现在使用 ASP.NET WebAPI 时,不能在同一个方法签名中使用多次 FromBodyAttribute 这个 Attribute 。正好我也在用 WebAPI,不过我还没有这种需求。所以就打算研究一下。

异常信息

  当使用多个 FromBodyAttribute 时,会收到下面的异常信息:

{
"Message": "An error has occurred.",
"ExceptionMessage": "Can't bind multiple parameters ('a' and 'b') to the request's content.",
"ExceptionType": "System.InvalidOperationException",
"StackTrace": " 在 System.Web.Http.Controllers.HttpActionBinding.ExecuteBindingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)\r\n 在 System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\r\n--- 引发异常的上一位置中堆栈跟踪的末尾 ---\r\n 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n 在 System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
}

意思就是不能参数 a 和 b 绑定到当前请求。

源代码追踪

  通过异常信息可以发现是在 HttpActionBinding 这个类里面抛出了这个异常。立马去源代码中找这个类。下面是源代码:

通过 1,2,3 这三个点,发现是参数绑定类里面的验证失败。接着看了 HttpParameterBinding 是个抽象类。没有看到太多可用信息。去 FromBodyAttribute 里面看看有没有什么可用信息。

发现这里需要提供一个 HttpParameterBinding 的实例。从箭头标记的方法根进去接着看。

  这里可以看到返回了一个 FormatterParameterBinding 的实例。并且需要三个参数。

  • parameter:从命名可以看出来是参数描述信息;
  • formatters:这个应该比较熟悉了,是格式化器;
  • bodyModelValidator:这个是对应参数的验证器;

  以上三个参数的意义基本就是看命名+大概阅读源代码得到的(所以写代码,命名很重要)。接着进入 FormatterParameterBinding 的源代码。这个类里面的代码也就 100 多行,逻辑就是从 HttpContent 中读取内容并设置为当前参数的值。

  到了这儿算是理清了一点:原来在参数上打的这些 Attribute 都是从 ParameterBindingAttribute 继承的,又通过实现 GetBinding(HttpParameterDescriptor parameter); 方法将请求的参数与方法的参数进行绑定。

  但是,在哪儿标记了不能使用多个 FromBodyAttribute 呢?既然是在 HttpActionBinding 中进行的验证,那就顺着 HttpActionBinding 往上找。通过 HttpActionBinding 的构造函数,发现只有 DefaultActionValueBinder 调用了它。接着往下看,看谁使用了这个 new 出来的实例。紧挨着就看到了 EnsureOneBodyParameter 这个方法,有点儿可疑,进去看一下。

  

  这个地方的 WillReadBody 如果为 true 并且 idxFromBody 大于 0 ,就会给 ParameterBinding 设置错误消息。看了一下消息内容,就是最上面的异常消息的模板。到这里应该算是找到根儿上了。

  现在来梳理一下:也就是说 HttpParameterBinding 的 WillReadBody 如果返回 true 就不能在一个方法的签名中使用多次,一旦使用多次,就会把这个错误。刚才上面看到的 FormatterParameterBinding 里面的 WillReadBody 是直接返回的 true ,而且是只读的,并且在执行绑定时是直接读取的 HttpContent 的内容,设置为当前参数的值了。假如要执行的 action 的方法签名中有多个参数就绑定不成功了。

定制开发

  知道了这个原理,那么想在一个有多个参数的 action 中进行参数的灵活绑定,就有了办法。分两步走:

  1. 自定义一个 Attribute 从 ParameterBindingAttribute 继承;
  2. 自定义一个 ParameterBinding 从 HttpParameterBinding 继承;在 ExecuteBindingAsync 方法中绑定 action 的参数的值。并把这个自定义的类的 WillReadBody 设置为 false 。

ASP.NET Web API 自定义 HttpParameterBinding的更多相关文章

  1. ASP.NET Web API 自定义MediaType实现jsonp跨域调用

    代码来自<ASP.NET Web API 2 框架揭秘>一书. 直接上代码: /// <summary> /// 自定义jsonp MediaType /// </sum ...

  2. ASP.NET WEB API 自定义模型校验过滤器

    对外公开WEB接口时,对模型校验是常见的安全常识,常见的写法是在controller中判断ModelState.IsValid,以注册用户API为例. Model: public class Regi ...

  3. 《ASP.NET Core跨平台开发从入门到实战》Web API自定义格式化protobuf

    <ASP.NET Core跨平台开发从入门到实战>样章节 Web API自定义格式化protobuf. 样章 Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于 ...

  4. ASP.NET Web API Model-ActionBinding

    ASP.NET Web API Model-ActionBinding 前言 前面的几个篇幅把Model部分的知识点划分成一个个的模块来讲解,而在控制器执行过程中分为好多个过程,对于控制器执行过程(一 ...

  5. 新作《ASP.NET Web API 2框架揭秘》正式出版

    我觉得大部分人都是“眼球动物“,他们关注的往往都是目光所及的东西.对于很多软件从业者来说,他们对看得见(具有UI界面)的应用抱有极大的热忱,但是对背后支撑整个应用的服务却显得较为冷漠.如果我们将整个“ ...

  6. ASP.NET Web API 2框架揭秘

    ASP.NET Web API 2框架揭秘(.NET领域再现力作顶级专家精讲微软全新轻量级通信平台) 蒋金楠 著   ISBN 978-7-121-23536-8 2014年7月出版 定价:108.0 ...

  7. Asp.Net Web API 2第十六课——Parameter Binding in ASP.NET Web API(参数绑定)

    导航 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html. 本文主要来讲解以下内容: ...

  8. ASP.NET Web API中的参数绑定总结

    ASP.NET Web API中的action参数类型可以分为简单类型和复杂类型. HttpResponseMessage Put(int id, Product item) id是int类型,是简单 ...

  9. Parameter Binding in ASP.NET Web API(参数绑定)

    Parameter Binding in ASP.NET Web API(参数绑定) 导航 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnbl ...

随机推荐

  1. php面向对象(一)---2017-04-17

    重点:定义类与实例化类:访问修饰符:构造函数 一.面向对象 面向对于与面向过程的主要区别在于:前者包含类和对象的概念 二.类和对象   1.类是由众多对象抽象(归纳总结)出来的东西  代表所有对象的特 ...

  2. 读《effective C++》1

    条款一:视C++为一个语言联邦 学习C++半个月了,学了他的面向过程编程,面向对象编程(封装性,继承性,多态性),template泛型编程,开始只是觉得C++基础是面向对象,但是学了这么多块开始有点迷 ...

  3. nginx视频直播/点播服务干货分享

    一.ubuntu14.04安装nginx及nginx_rtmp_module扩展 nginx根据是否已安装和安装的方式不同,有一下三种方式安装及扩展安装. 1.全新安装nginx和nginx_rtmp ...

  4. struts1实现简单的登录功能(附源码)

    环境:MyEclipse 14                                                                                     ...

  5. [.NET] 《Effective C#》读书笔记(二)- .NET 资源托管

    <Effective C#>读书笔记(二)- .NET 资源托管 简介 续 <Effective C#>读书笔记(一)- C# 语言习惯. .NET 中,GC 会帮助我们管理内 ...

  6. 【Vue 入门】使用 Vue2 开发一个展示项目列表的应用

    前言 一直没有找到一个合适的展示个人项目的模板,所以自己动手使用 Vue 写了一个.该模板基于 Markdown 文件进行配置,只需要按一定规则编写 Markdown 文件,然后使用一个 在线工具 转 ...

  7. PHP 手册

    http://www.php.net/manual/zh/index.php 感谢中文翻译工作者. PHP 手册¶ by:Mehdi Achour Friedhelm Betz Antony Dovg ...

  8. 如何设置文本不换行省略号显示等CSS常用文本属性

    如何让多余的文本省略号显示首先要说几个属性的作用: whitespace:nowrap 中文行末不断行显示 overflow: 控制超出文本的显示方式:hidden 超出范围文本隐藏:scroll 始 ...

  9. 产品经理学Python:条件控制

    条件控制其实就是if...else...(如果...条件是成立的,就做...:反之,就做...)的使用,其基本结构是: 具体看下面这个例子: def account_login(): # 定义函数 p ...

  10. iOS 制作自动打包脚本 Xcode8.3.2

    本文包含以下内容: 前言 1.shell脚本的编写 2.xcodebuild命令 3.完整的可用示例 参考资料 前言 做iOS开发,打包APP是比较频繁的事情,每次都手动去配置一堆东西确实是比较乏味. ...