.NET Core WebApi中实现多态数据绑定

什么是多态数据绑定?

我们都知道在ASP.NET Core WebApi中数据绑定机制(Data Binding)负责绑定请求参数, 通常情况下大部分的数据绑定都能在默认的数据绑定器(Binder)中正常的进行,但是也会出现少数不支持的情况,例如多态数据绑定。所谓的多态数据绑定(polymorphic data binding),即请求参数是子类对象的Json字符串, 而action中定义的是父类类型的变量,默认情况下ASP.NET Core WebApi是不支持多态数据绑定的,会造成数据丢失。

以下图为例

640?wx_fmt=png

 

 

Person类是一个父类,Doctor类和Student类是Person类的派生类。Doctor类中持有的HospitalName属性,Student中持有的SchoolName属性。

 

接下來我们创建一个Web Api项目并添加一个PeopleController。

在PeopleController中我们添加一个Add api,并将请求数据直接返回,以便查看效果。

640?wx_fmt=png

这里我们使用Postman请求这个api, 请求的Content-Type是application/json, 请求的Body内容如下。

640?wx_fmt=png

请求的返回内容

640?wx_fmt=png

返回结果和我们希望得到的结果不太一样,Student持有的SchoolName属性和Doctor持有的HospitalName属性都丢失了。

现在我们启动项目调试模式,重新使用Postman请求一次,得到的结果如下

640?wx_fmt=png

 

People集合中存放3个People类型的对象, 没有出现我们期望的Student类型对象和Doctor类型对象,这说明.NET Core WebApi默认是不支持多态数据绑定的,如果使用父类类型变量来接收数据,Data Binding只会实例化父类对象,而非一个派生类对象, 从而导致属性丢失。 

自定义JsonConverter来实现多态数据绑定

JsonConverter是Json.NET中的一个类,主要负责Json对象的序列化和反序列化。

首先我们创建一个泛型类JsonCreationConverter,并继承了JsonConverter类,代码如下:

640?wx_fmt=png

其中,我们加入了一个抽象方法Create,这个方法会负责根据Json字符串的内容,返回一个泛型类型对象,这里既可以返回一个当前泛型类型的对象,也可以返回一个当前泛型类型派生类的对象。JObject是Json.NET中的Json字符串读取器,负责读取Json字符串中属性的值。

另外我们还复写了ReadJson方法,在ReadJson中我们会先调用Create方法获取一个当前泛型类对象或者当前泛型类的派生类对象Json.NET中默认的KeyValuePairConverter会直接实例化当前参数类型对象,这也就是默认不支持多态数据绑定的主要原因,serializer.Popluate方法的作用是将Json字符串的内容映射到目标对象(当前泛型类对象或者当前泛型类的派生类对象)的对应属性。

这里由于我们只需要读取Json, 所以WriteJson的方法我们不需要实现,CanWrite属性我们也强制返回了False。 

第二步,我们创建一个PersonJsonConverter类,它继承了JsonCreationConverter<Person>, 其代码如下

640?wx_fmt=png

在这个类中我们复写了Create方法,这里我们使用JObject来获取Json字符串中拥有的属性。

  • 如果字符串中包含schoolName属性,就返回一个新的Student对象

  • 如果字符串中包含hospitalName属性,就返回一个新的Doctor对象

  • 否则,返回一个新Person对象

最后一步,我们在Person类中使用特性标注Person类使用PersonJsonConverter来进行转换Json序列化和反序列化。

640?wx_fmt=png

现在我们重新使用调试模式启动程序, 然后使用Postman请求当前api

640?wx_fmt=png

 我们会发现,people集合中已经正确绑定了的派生子类类型对象,最终Postman上我们得到以下响应结果

640?wx_fmt=png

至此多态数据绑定成功。 

刨根问底

为什么添加了一个PersonJsonConverter类,多态绑定就实现了呢?

让我们来一起Review一下MVC Core以及Json.NET的代码。 

首先我们看一下MvcCoreMvcOptionsSetup代码

640?wx_fmt=png

MvcCoreMvcOptionsSetup类中的Configure方法设置了默认数据绑定使用Provider列表。

当一个api参数被标记为[FromBody]时,BodyModelBinderProvider会实例化一个BodyModelBinder对象来处理这个参数并尝试进行数据绑定。 

BodyModelBinder类中有一个BindModelAsync方法,从名字的字面意思上我们很清楚的知道这个方法就是用来绑定数据的。

640?wx_fmt=png

在这个方法中它会尝试寻找一个匹配的IInputFormatter对象来绑定数据,由于这时候请求的Content-Type是application/json, 所以这里会使用JsonInputFormatter对象来进行数据绑定。 

下面我们看一下JsonInputFormatter类的部分关键代码

640?wx_fmt=png

JsonInputFormatter类中的ReadRequestBodyAsync方法负责数据绑定在该方法中使用了Json.NETJsonSerializer类的Deserialize方法来进行反序列化, 这说明Mvc Core的底层是直接使用Json.NET来操作Json的。 

JsonSerializer类的部分关键代码

640?wx_fmt=png

JsonSerializer会调用JsonSerializerInternalReader类的Deserialize方法将Json字符串内容反序列化。

最终我们看一下JsonSerializerInternalReader中的部分关键代码

640?wx_fmt=png

JsonSerializerInternalReader类里面的Deserialize方法会尝试根据当前请求参数的类型,去查找并实例化一个合适的JsonConverter。 如果查找到匹配的Converter, 就使用该Converter进行实际的反序列化数据绑定操作。在当前例子中由于api的参数类型是Person,所以它会匹配到PersonJsonConverter, 这就是为什么我们通过添加PersonJsonConverter就完成了多态数据绑定的功能。


原文地址:https://www.cnblogs.com/lwqlun/p/9532803.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/320033.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【期望】期望分数(金牌导航 期望-4)

期望分数 金牌导航 期望-4 题目大意 告诉你一个01串中每个位置是1的概率&#xff0c;对于连续的x个1&#xff0c;贡献为x3x^3x3&#xff0c;问你期望贡献是多少 输入样例 3 0.5 0.5 0.5输入样例 6.0数据范围 1⩽N⩽1051\leqslant N \leqslant 10^51⩽N⩽105 解题思路…

[51NOD1847]奇怪的数学题(杜教筛+min_25筛+第二类斯特林数)

f(x)f(x)f(x)表示xxx的次大约数&#xff0c;有f(x)xx的最小质因数f(x)\frac{x}{x的最小质因数}f(x)x的最小质因数x​&#xff0c;那么 ∑i1n∑j1nsgcd(i,j)k∑i1n∑j1nf(gcd(i,j))k∑d1nf(d)k∑i1n∑j1n[gcd(i,j)d]∑d1nf(d)k∑i1⌊nd⌋∑j1⌊nd⌋[gcd(i,j)1]∑d1nf(d)k⋅(2∑i…

hdu 1059 Dividing

Hdu链接 文章目录题目描述题意&#xff1a;题解&#xff1a;代码&#xff1a;题目描述 输入描述: 输出描述: 示例1 输入 1 0 1 2 0 0 1 0 0 0 1 1 0 0 0 0 0 0输出 Collection #1: Cant be divided.Collection #2: Can be divided.题意&#xff1a; 有价值分别是1~6的6种…

UOJ#284-快乐游戏鸡【长链剖分,线段树】

正题 题目链接:https://uoj.ac/problem/284 题目大意 nnn个点的一棵树&#xff0c;每个点有一个wiw_iwi​表示至少死亡wiw_iwi​次才能通过这个点&#xff0c;否则就会死亡。只能往子节点走&#xff0c;mmm此询问从sis_isi​走到tit_iti​至少要死多少次。 解题思路 也就算我…

【期望】彩色圆环(金牌导航 期望-5)

彩色圆环 金牌导航 期望-5 题目大意 给你一个环&#xff0c;每个位置的数字等概率为1~m中的其中一个&#xff0c;对于连续的相同数字的串&#xff0c;记其长度为aia_iai​&#xff0c;求aia_iai​的积的期望值 输入样例 8 1输出样例 8.00000数据范围 1⩽N⩽200,1⩽M⩽109…

概率与期望技巧随记

1.已知某事件发生的概率为ppp&#xff0c;则要让该事件发生所需的试验次数期望值为1p\frac{1}{p}p1​ 证明&#xff1a;Exp1(1−p)(Ex1)E_xp\times 1(1-p)\times(E_x1)Ex​p1(1−p)(Ex​1) 易解得Ex1pE_x\frac{1}{p}Ex​p1​

P2597-[ZJOI2012]灾难【DAG支配树】

正题 题目链接:https://www.luogu.com.cn/problem/P2597 题目大意 nnn个点的一张DAGDAGDAG&#xff0c;对于每个点xxx求有多少点yyy满足从yyy出发到达某个出度为000的所有路径都必须经过xxx。 解题思路 首先建立一张反图&#xff0c;然后一个超级源点连向所有入度为000的节点…

hdu-1171 Big Event in HDU

hdu试题链接 文章目录Problem Description题意&#xff1a;题解&#xff1a;代码&#xff1a;Problem Description Nowadays, we all know that Computer College is the biggest department in HDU. But, maybe you don’t know that Computer College had ever been split in…

.Net Core应用框架Util介绍(二)

Util的开源地址https://github.com/dotnetcore/utilUtil的开源协议Util以MIT协议开源&#xff0c;这是目前最宽松的开源协议&#xff0c;你不仅可以用于商业项目&#xff0c;还能把Util的代码放进你的框架&#xff0c;放心使用。Util的命名Util这个名字看上去不怎么高大上&…

【期望】【高斯消元】图上游走(金牌导航 期望-6)

图上游走 金牌导航 期望-6 题目大意 给出一个无向连通图&#xff0c;小明初始在点1&#xff0c;每一步等概率地走向相连的其他点&#xff0c;当走到n时结束&#xff0c;定义分数从1为走到n的过程中经过的边的编号之和&#xff0c;现在让你给这m条边重新编号&#xff0c;使最…

[CSA35G][XSY3318]Counting Quests (DP)

XSY3318 CSA35G 对于一个询问区间的集合SSS&#xff0c;求出每一个数被哪些区间覆盖了&#xff0c;记为SiS_iSi​。 要能保证猜出选中数&#xff0c;当且仅当每个数的SiS_iSi​互不相同。 考虑求出不满足要求的集合SSS的个数。 首先可以观察得到SiS_iSi​的一个性质&#xff1…

hdu-1114 Piggy-Bank

文章目录Problem Description题意&#xff1a;题解&#xff1a;代码&#xff1a;hdu-1114Problem Description Before ACM can do anything, a budget must be prepared and the necessary financial support obtained. The main income for this action comes from Irreversib…

ATcoder-[AGC048B]Bracket Score【结论,贪心】

正题 题目链接:https://atcoder.jp/contests/agc048/tasks/agc048_b 题目大意 长度为nnn的合法括号序列可以包含[...][...][...]和(...)(...)(...)。 如果在第iii个位置是′(′\ (\ ′ ( ′ 或者 ′)′\ )\ ′ ) ′那么可以获得aia_iai​的权值&#xff0c;否则获得bib_ibi​…

.Net架构篇:实用中小型公司支付中心设计

前言说起支付平台&#xff0c;支付宝量级的支付平台和一个小型公司的支付不可同日耳语。一个初创或刚创业一两年的公司&#xff0c;一没人力&#xff0c;二没财力的情况下&#xff0c;如果也想对接支付那怎么办呢&#xff1f;感谢支付宝和微信支付&#xff0c;两大行业巨头提供…

【期望】选书问题(金牌导航 期望-7)

选书问题 金牌导航 期望-7 题目大意 有n个人&#xff0c;每个人有自己的选书目录&#xff0c;一个人有p的概率选当前的书&#xff0c;有1-p的概率不选&#xff0c;即去查看下一本书&#xff08;过n后回到1&#xff09;&#xff0c;现在问你选书的逆序对的期望数 输入样例 …

[CSA49G][XSY3315] Bunny on Number Line (DP)

CSA49G XSY3315 因为判断两串是否本质不同只看某几项是不是好数&#xff0c;与究竟是哪个好数无关&#xff0c;所以考虑转换一下题意&#xff1a; 给出一个长度为aka_kak​的01串SSS&#xff0c;第a1,a2,...,aka_1,a_2,...,a_ka1​,a2​,...,ak​项为1&#xff0c;其余项为0。 …

Rabbit的工作(2)

牛客网 文章目录题目描述题解&#xff1a;代码&#xff1a;题目描述 Rabbit通过了上次boss的考核&#xff0c;现在她又遇到了一个问题。 Rabbit接到了K个任务&#xff0c;每个任务她可以自由选择用i天去完成(1≤ i≤ N)。刁钻的boss想让Rabbit恰好用W天完成所有任务。 已知Rabb…

jzoj6065-[NOI2019模拟2019.3.18]One?One!【FFT】

正题 题目链接:https://gmoj.net/senior/#main/show/6065 题目大意 oneness(x)oneness(x)oneness(x)表示xxx的约数中全是111的数的个数&#xff0c;给出一个长度为lll的随机生成的数nnn&#xff0c;求∑i1noneness(i)\sum_{i1}^noneness(i)i1∑n​oneness(i) 解题思路 转换一…

netcore编程之后面对不习惯的xshell黑屏部署,是时候使用jenkins自动化发布工具了...

在很久之前net还只能在windows上部署的时候&#xff0c;或许很多创业公司的朋友发布项目还都是人肉部署&#xff0c;反正windows都是可视化的界面&#xff0c;拖拖拉拉&#xff0c;开开关关还不是特别麻烦。。。现如今你的项目需要在linux上部署&#xff0c;可惜的是再也没有什…

【期望】关灯游戏(金牌导航 期望-8)

关灯游戏 金牌导航 期望-8 题目大意 有n盏灯&#xff0c;有些是亮的&#xff0c;有的是暗的&#xff0c;现在如果按一个位置的开关&#xff0c;那么是它因数的位置的灯都会改变开关情况&#xff0c;现在如果用k步不能直接关完&#xff0c;就随机按&#xff0c;直到可以k步关…