ASP.NET Web API 自定义 HttpParameterBinding
背景
问题的起因是这样的。群里面一个哥们儿发现在使用 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 中进行参数的灵活绑定,就有了办法。分两步走:
- 自定义一个 Attribute 从 ParameterBindingAttribute 继承;
- 自定义一个 ParameterBinding 从 HttpParameterBinding 继承;在 ExecuteBindingAsync 方法中绑定 action 的参数的值。并把这个自定义的类的 WillReadBody 设置为 false 。
ASP.NET Web API 自定义 HttpParameterBinding的更多相关文章
- ASP.NET Web API 自定义MediaType实现jsonp跨域调用
代码来自<ASP.NET Web API 2 框架揭秘>一书. 直接上代码: /// <summary> /// 自定义jsonp MediaType /// </sum ...
- ASP.NET WEB API 自定义模型校验过滤器
对外公开WEB接口时,对模型校验是常见的安全常识,常见的写法是在controller中判断ModelState.IsValid,以注册用户API为例. Model: public class Regi ...
- 《ASP.NET Core跨平台开发从入门到实战》Web API自定义格式化protobuf
<ASP.NET Core跨平台开发从入门到实战>样章节 Web API自定义格式化protobuf. 样章 Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于 ...
- ASP.NET Web API Model-ActionBinding
ASP.NET Web API Model-ActionBinding 前言 前面的几个篇幅把Model部分的知识点划分成一个个的模块来讲解,而在控制器执行过程中分为好多个过程,对于控制器执行过程(一 ...
- 新作《ASP.NET Web API 2框架揭秘》正式出版
我觉得大部分人都是“眼球动物“,他们关注的往往都是目光所及的东西.对于很多软件从业者来说,他们对看得见(具有UI界面)的应用抱有极大的热忱,但是对背后支撑整个应用的服务却显得较为冷漠.如果我们将整个“ ...
- ASP.NET Web API 2框架揭秘
ASP.NET Web API 2框架揭秘(.NET领域再现力作顶级专家精讲微软全新轻量级通信平台) 蒋金楠 著 ISBN 978-7-121-23536-8 2014年7月出版 定价:108.0 ...
- 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. 本文主要来讲解以下内容: ...
- ASP.NET Web API中的参数绑定总结
ASP.NET Web API中的action参数类型可以分为简单类型和复杂类型. HttpResponseMessage Put(int id, Product item) id是int类型,是简单 ...
- Parameter Binding in ASP.NET Web API(参数绑定)
Parameter Binding in ASP.NET Web API(参数绑定) 导航 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnbl ...
随机推荐
- Asp .Net MVC4笔记之走进MVC
一.MVC三层架构: mvc三层架构,大家都比较熟悉了,这里再介绍一下.Mvc将应用程序分离为三个部分: Model:是一组类,用来描述被处理的数据,同时也定义这些数据如何被变更和操作的业务规则.与数 ...
- 优雅地解决Ajax接口参数来自另一个接口的问题
最近闲赋在家,终于有时间回顾我在工作中遇到的一些东西,由于经验不足,有些方面做的不是很好.在上家公司曾经遇到一个小问题,就是Ajax的接口中有参数是从另一个接口后台传来的.当时我的做法是将需要参数的接 ...
- ionic打包项目,运行时报错A problem occurred configuring root project 'android'。。。
运行报错的原因是sdk没有下载完整 解决办法: 1,打开sdk manage.分别下载android support repository.Google play services.google re ...
- 设备像素,设备独立像素,CSS像素
之前学了移动端的开发对设备像素.设备独立像素.CSS像素弄得不太清楚,所以趁周末的时间查了一下,稍加整理 一些概念 在进行具体的分析之前,首先得知道下面这些关键性基本概念. CSS像素 CSS像素是W ...
- Java泛型知识点:泛型类、泛型接口和泛型方法
有许多原因促成了泛型的出现,而最引人注意的一个原因,就是为了创建容器类. 泛型类 容器类应该算得上最具重用性的类库之一.先来看一个没有泛型的情况下的容器类如何定义: public class Cont ...
- C语言学习的第一章
首先,学习编写程序要先知道什么是程序,我们为什么要写程序? 程序就是为了让计算机执行某些操作或解决某个问题而编写的一系列有序指令的集合.程序里有很多算法,算法是解决问题的具体方法和步骤,就像我们想要得 ...
- Golang 在mac上用VSCode开发、Delve调试
本文包含以下内容: 1.安装VSCode: 2.用Delve调试Go项目: 3.自定义代码片段: 1.安装VSCode 先去下载VSCode,这个链接里面也有官方文档. 安装插件: vscode-ic ...
- (知识点)JavaScript继承
1)原型链 ①原型链示例 function Shape() { this.name = 'shape'; this.toString = function(){ return this.name; } ...
- webUI自动化测试框架---”pyswat“介绍
webUI自动化测试框架---"pyswat"介绍 大家好我是lamecho 辣么丑,今天给大家介绍一款web自动化测试框架pyswat. "pyswat"是 ...
- session知识总结
0.什么是会话? - 简单理解:打开浏览器到关闭浏览器过程中的操作.请求. 1.Session是什么? - session是HttpSession的简称: - 用于保存会话状态: - 将会话状态保存在 ...