背景

  问题的起因是这样的。群里面一个哥们儿发现在使用 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. swfupload多图上传插件(ASP.NET)

    <script src="../js/swfupload/swfupload.js" type="text/javascript"></scr ...

  2. python os模块常用方法

    OS模块是Python标准库中的一个操作模块,主要用于处理Linux操作系统中的文件和目录 1.要使用OS必须先导入OS import os 2.os.getcwd()获取当前路径. print os ...

  3. Apache日志分割

    1.cronolog安装 采用 cronolog 工具进行 apache 日志分割 http://download.chinaunix.net/download.php?id=3457&Res ...

  4. [Java自学第二天]

    Java封装性思想的初步理解 从项目需求的角度出发,建立各个模块化的类,各个模块暂时不需要具体的方法描述,只需要各个模块的理想到位. 以银行项目为例 初步设想需要三个模块:银行(Bank类).客户(C ...

  5. 【转载】GPIO模拟i2c通信

    I2C总线的通信过程(见图4-8)主要包含三个主要阶段:起始阶段.数据传输阶段和终止阶段. 1. 起始阶段 在I2C总线不工作的情况下,SDA(数据线)和SCL(时钟线)上的信号均为高电平.如果此时主 ...

  6. 跨域问题解决方案(HttpClient安全跨域 & jsonp跨域)

    1 错误场景 今天要把项目部署到外网的时候,出现了这样的问题, 我把两个项目放到自己本机的tomcat下, 进行代码调试, 运行 都没有问题的, 一旦把我需要调用接口的项目B放到其他的服务器上, 就会 ...

  7. 记录JavaFx中非常重要的细节,入门了也未必知道

    title: 记录JavaFx中非常重要的细节 JavaFx中有一些疑难杂症,或许你以为你掌握了JavaFx,但是也未必知道我所说的这些问题和解决方案,如果有帮助到你的,可以加群最大最活跃的JavaF ...

  8. 小米红米1 android 4.4.4上操作数据库异常问题

    产生的问题: 小米红米1 android 4.4.4上,按HOME键,应用进入后台,再启动,应用进程直接挂掉 解决的方法: 这个是操作数据库,数据库关闭之后导致的异常,解决的方法: //4.0以上的版 ...

  9. 6.1熟知tsung.xml配置文件(翻译)

    6.1.文件结构 默认的encoding是utf-8,你也可以使用以下不同的encoding:<?xml version="1.0" encoding="ISO-8 ...

  10. GreenDao

    前言 我相信,在平时的开发过程中,大家一定会或多或少地接触到 SQLite.然而在使用它时,我们往往需要做许多额外的工作,像编写 SQL 语句与解析查询结果等.所以,适用于 Android 的ORM ...