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