什么是.NET Core?
随着2014年 Xamarin和微软发起.NET基金会,微软在2014年11月份 开放.NET框架源代码。在.NET开源基金会的统一规划下诞生了.NET Core 。也就是说.NET Core Framework是参考.NET Framework重新开发的.NET实现,Mono是.NET Framework的一个开源的、跨平台的实现。
本文主要介绍了关于.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,并将请求数据直接返回,以便查看效果。
[Route("api/people")] public class PeopleController : Controller { [HttpPost] [Route("")] public List<Person> Add([FromBody]List<Person> people) { return people; } }
这里我们使用Postman请求这个api, 请求的Content-Type是application/json, 请求的Body内容如下。
[{ firstName: 'Mike', lastName: 'Li' }, { firstName: 'Stephie', lastName: 'Wang', schoolName: 'No.15 Middle School' }, { firstName: 'Jacky', lastName: 'Chen', hospitalName: 'Center Hospital' }]
请求的返回内容
[ { "FirstName": "Mike", "LastName": "Li" }, { "FirstName": "Stephie", "LastName": "Wang" }, { "FirstName": "Jacky", "LastName": "Chen" } ]
返回结果和我们希望得到的结果不太一样,Student持有的SchoolName属性和Doctor持有的HospitalName属性都丢失了。
现在我们启动项目调试模式,重新使用Postman请求一次,得到的结果如下
People集合中存放3个People类型的对象, 没有出现我们期望的Student类型对象和Doctor类型对象,这说明.NET Core WebApi默认是不支持多态数据绑定的,如果使用父类类型变量来接收数据,Data Binding只会实例化父类对象,而非一个派生类对象, 从而导致属性丢失。
自定义JsonConverter来实现多态数据绑定
JsonConverter是Json.NET中的一个类,主要负责Json对象的序列化和反序列化。
首先我们创建一个泛型类JsonCreationConverter,并继承了JsonConverter类,代码如下:
public abstract class JsonCreationConverter<T> : JsonConverter { public override bool CanWrite { get { return false; } } protected abstract T Create(Type objectType, JObject jObject); public override bool CanConvert(Type objectType) { return typeof(T).IsAssignableFrom(objectType); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader == null) throw new ArgumentNullException("reader"); if (serializer == null) throw new ArgumentNullException("serializer"); if (reader.TokenType == JsonToken.Null) return null; JObject jObject = JObject.Load(reader); T target = Create(objectType, jObject); serializer.Populate(jObject.CreateReader(), target); return target; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } }
其中,我们加入了一个抽象方法Create,这个方法会负责根据Json字符串的内容,返回一个泛型类型对象,这里既可以返回一个当前泛型类型的对象,也可以返回一个当前泛型类型派生类的对象。JObject是Json.NET中的Json字符串读取器,负责读取Json字符串中属性的值。
另外我们还复写了ReadJson方法,在ReadJson中我们会先调用Create方法获取一个当前泛型类对象或者当前泛型类的派生类对象(Json.NET中默认的KeyValuePairConverter会直接实例化当前参数类型对象,这也就是默认不支持多态数据绑定的主要原因),serializer.Popluate方法的作用是将Json字符串的内容映射到目标对象(当前泛型类对象或者当前泛型类的派生类对象)的对应属性。
这里由于我们只需要读取Json, 所以WriteJson的方法我们不需要实现,CanWrite属性我们也强制返回了False。
第二步,我们创建一个PersonJsonConverter类,它继承了JsonCreationConverter<Person>, 其代码如下