.NET Core WebApi中实现多态数据绑定
什么是多態(tài)數(shù)據(jù)綁定?
我們都知道在ASP.NET Core WebApi中數(shù)據(jù)綁定機(jī)制(Data Binding)負(fù)責(zé)綁定請(qǐng)求參數(shù), 通常情況下大部分的數(shù)據(jù)綁定都能在默認(rèn)的數(shù)據(jù)綁定器(Binder)中正常的進(jìn)行,但是也會(huì)出現(xiàn)少數(shù)不支持的情況,例如多態(tài)數(shù)據(jù)綁定。所謂的多態(tài)數(shù)據(jù)綁定(polymorphic data binding),即請(qǐng)求參數(shù)是子類對(duì)象的Json字符串, 而action中定義的是父類類型的變量,默認(rèn)情況下ASP.NET Core WebApi是不支持多態(tài)數(shù)據(jù)綁定的,會(huì)造成數(shù)據(jù)丟失。
以下圖為例
?
?
Person類是一個(gè)父類,Doctor類和Student類是Person類的派生類。Doctor類中持有的HospitalName屬性,Student中持有的SchoolName屬性。
?
接下來我們創(chuàng)建一個(gè)Web Api項(xiàng)目并添加一個(gè)PeopleController。
在PeopleController中我們添加一個(gè)Add api,并將請(qǐng)求數(shù)據(jù)直接返回,以便查看效果。
這里我們使用Postman請(qǐng)求這個(gè)api, 請(qǐng)求的Content-Type是application/json, 請(qǐng)求的Body內(nèi)容如下。
請(qǐng)求的返回內(nèi)容
返回結(jié)果和我們希望得到的結(jié)果不太一樣,Student持有的SchoolName屬性和Doctor持有的HospitalName屬性都丟失了。
現(xiàn)在我們啟動(dòng)項(xiàng)目調(diào)試模式,重新使用Postman請(qǐng)求一次,得到的結(jié)果如下
?
People集合中存放3個(gè)People類型的對(duì)象, 沒有出現(xiàn)我們期望的Student類型對(duì)象和Doctor類型對(duì)象,這說明.NET Core WebApi默認(rèn)是不支持多態(tài)數(shù)據(jù)綁定的,如果使用父類類型變量來接收數(shù)據(jù),Data Binding只會(huì)實(shí)例化父類對(duì)象,而非一個(gè)派生類對(duì)象, 從而導(dǎo)致屬性丟失。?
自定義JsonConverter來實(shí)現(xiàn)多態(tài)數(shù)據(jù)綁定
JsonConverter是Json.NET中的一個(gè)類,主要負(fù)責(zé)Json對(duì)象的序列化和反序列化。
首先我們創(chuàng)建一個(gè)泛型類JsonCreationConverter,并繼承了JsonConverter類,代碼如下:
其中,我們加入了一個(gè)抽象方法Create,這個(gè)方法會(huì)負(fù)責(zé)根據(jù)Json字符串的內(nèi)容,返回一個(gè)泛型類型對(duì)象,這里既可以返回一個(gè)當(dāng)前泛型類型的對(duì)象,也可以返回一個(gè)當(dāng)前泛型類型派生類的對(duì)象。JObject是Json.NET中的Json字符串讀取器,負(fù)責(zé)讀取Json字符串中屬性的值。
另外我們還復(fù)寫了ReadJson方法,在ReadJson中我們會(huì)先調(diào)用Create方法獲取一個(gè)當(dāng)前泛型類對(duì)象或者當(dāng)前泛型類的派生類對(duì)象(Json.NET中默認(rèn)的KeyValuePairConverter會(huì)直接實(shí)例化當(dāng)前參數(shù)類型對(duì)象,這也就是默認(rèn)不支持多態(tài)數(shù)據(jù)綁定的主要原因),serializer.Popluate方法的作用是將Json字符串的內(nèi)容映射到目標(biāo)對(duì)象(當(dāng)前泛型類對(duì)象或者當(dāng)前泛型類的派生類對(duì)象)的對(duì)應(yīng)屬性。
這里由于我們只需要讀取Json, 所以WriteJson的方法我們不需要實(shí)現(xiàn),CanWrite屬性我們也強(qiáng)制返回了False。?
第二步,我們創(chuàng)建一個(gè)PersonJsonConverter類,它繼承了JsonCreationConverter<Person>, 其代碼如下
在這個(gè)類中我們復(fù)寫了Create方法,這里我們使用JObject來獲取Json字符串中擁有的屬性。
如果字符串中包含schoolName屬性,就返回一個(gè)新的Student對(duì)象
如果字符串中包含hospitalName屬性,就返回一個(gè)新的Doctor對(duì)象
否則,返回一個(gè)新Person對(duì)象
最后一步,我們?cè)赑erson類中使用特性標(biāo)注Person類使用PersonJsonConverter來進(jìn)行轉(zhuǎn)換Json序列化和反序列化。
現(xiàn)在我們重新使用調(diào)試模式啟動(dòng)程序, 然后使用Postman請(qǐng)求當(dāng)前api
?我們會(huì)發(fā)現(xiàn),people集合中已經(jīng)正確綁定了的派生子類類型對(duì)象,最終Postman上我們得到以下響應(yīng)結(jié)果
至此多態(tài)數(shù)據(jù)綁定成功。?
刨根問底
為什么添加了一個(gè)PersonJsonConverter類,多態(tài)綁定就實(shí)現(xiàn)了呢?
讓我們來一起Review一下MVC Core以及Json.NET的代碼。?
首先我們看一下MvcCoreMvcOptionsSetup代碼
MvcCoreMvcOptionsSetup類中的Configure方法設(shè)置了默認(rèn)數(shù)據(jù)綁定使用Provider列表。
當(dāng)一個(gè)api參數(shù)被標(biāo)記為[FromBody]時(shí),BodyModelBinderProvider會(huì)實(shí)例化一個(gè)BodyModelBinder對(duì)象來處理這個(gè)參數(shù)并嘗試進(jìn)行數(shù)據(jù)綁定。?
BodyModelBinder類中有一個(gè)BindModelAsync方法,從名字的字面意思上我們很清楚的知道這個(gè)方法就是用來綁定數(shù)據(jù)的。
在這個(gè)方法中它會(huì)嘗試尋找一個(gè)匹配的IInputFormatter對(duì)象來綁定數(shù)據(jù),由于這時(shí)候請(qǐng)求的Content-Type是application/json, 所以這里會(huì)使用JsonInputFormatter對(duì)象來進(jìn)行數(shù)據(jù)綁定。?
下面我們看一下JsonInputFormatter類的部分關(guān)鍵代碼
JsonInputFormatter類中的ReadRequestBodyAsync方法負(fù)責(zé)數(shù)據(jù)綁定,?在該方法中使用了Json.NET的JsonSerializer類的Deserialize方法來進(jìn)行反序列化, 這說明Mvc Core的底層是直接使用Json.NET來操作Json的。?
JsonSerializer類的部分關(guān)鍵代碼
JsonSerializer會(huì)調(diào)用JsonSerializerInternalReader類的Deserialize方法將Json字符串內(nèi)容反序列化。
最終我們看一下JsonSerializerInternalReader中的部分關(guān)鍵代碼
JsonSerializerInternalReader類里面的Deserialize方法會(huì)嘗試根據(jù)當(dāng)前請(qǐng)求參數(shù)的類型,去查找并實(shí)例化一個(gè)合適的JsonConverter。?如果查找到匹配的Converter, 就使用該Converter進(jìn)行實(shí)際的反序列化數(shù)據(jù)綁定操作。在當(dāng)前例子中由于api的參數(shù)類型是Person,所以它會(huì)匹配到PersonJsonConverter, 這就是為什么我們通過添加PersonJsonConverter就完成了多態(tài)數(shù)據(jù)綁定的功能。
原文地址:https://www.cnblogs.com/lwqlun/p/9532803.html
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號(hào)文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的.NET Core WebApi中实现多态数据绑定的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《.NET 性能优化》送书活动结果公布
- 下一篇: .Net Core应用框架Util介绍(