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 ...
随机推荐
- JS中的函数、Bom、DOM及JS事件
本期博主给大家带来JS的函数.Bom.DOM操作,以及JS各种常用的数据类型的相关知识,同时,这也是JavaScript极其重要的部分,博主将详细介绍各种属性的用法和方法. 一.JS中的函数 [函数的 ...
- Web性能优化工具WebPageTest(二)——性能数据
在前一篇<配置>完成后,点击“START TEST”,就可以开始测试,测试需要一段时间. 有时候可能还要排队,如下图所示,测试完成后可查看到测试结果. 一.Summary 1)优化等级 优 ...
- 2 安装redis.md
cnblogs-DOC 1.服务器环境 2.安装Redis3.安装Zookeeper4.安装MPush5.安装Alloc服务6.完整测试7.常见问题 一.Linux系统安装Redis 官网下载Redi ...
- 通过VMware安装Linux操作系统
1.安装好vmvare,下载好Linux,本文采用redhat 6.5 (下载linux可参考http://www.linuxidc.com/Linux/2007-09/7399.htm) 2.选择 ...
- angular购物车
<body ng-app> <div class="container" ng-controller="carController"> ...
- 简单的RTSP消息交互过程
C表示RTSP客户端,S表示RTSP服务端 第一步:查询服务器端可用方法 1. C->S:OPTION request //询问S有哪些方法可用 2. S->C:OPTION ...
- spring 动态创建数据源
项目需求如下,公司对外提供服务,公司本身有个主库,另外公司会为每个新客户创建一个数据库,客户的数据库地址,用户名,密码,都保存在主数据库中.由于不断有新的客户加入,所以要求,项目根据主数据库中的信息, ...
- 简单的后台数据和前台数据交互.net
最近忙着做POS项目,心血来来潮写了点小项目. 更具要求是随机显示数据并且产生的数据是可以控制的.前台交互显示能够倒叙,切每次只显示一条,页面不能超过20条超过的部分做删除. 我先展示一下前台的代码, ...
- 读书笔记 effective c++ Item 54 让你自己熟悉包括TR1在内的标准库
1. C++0x的历史渊源 C++标准——也就是定义语言的文档和程序库——在1998被批准.在2003年,一个小的“修复bug”版本被发布.然而标准委员会仍然在继续他们的工作,一个“2.0版本”的C+ ...
- Google Firebase Unity接入的坑
就说跑demo碰到的坑吧 https://firebase.google.com/docs/unity/setup 这是Firebase Unity的setup指南 大概写写步骤: 1. Fireba ...