( json.net deserilize dirven class problem! )
前情提要:
開發 web, server 與 client 透過 json 格式傳遞資料,server 端在定義 ViewMode 時,DataModel 可能是 ChildAModel 或 ChildBModel 類別,
以 OO多型 ( Polymorphism ) 的設計來說,
實作一個父類 ( BaseModel ) 讓 ChildAModel, ChildBModel 繼承,
這樣 ViewModel.DataModel 就可以指定 ChildAModel, ChildBModel 其中之一的資料格式
如下:
public class BaseModel { public int key { get; set; } } public class ChildAModel: BaseModel { public string Name { get; set; } public int Age { get; set; } } public class ChildBModel : BaseModel { public string SomeProperty1 { get; set; } public int SomeProperty2 { get; set; } } public class ViewModel { public BaseModel DataModel { get; set; } }
問題:
依這樣的設計,將 ViewModel 的資料轉成 JSON 拋給 Client 沒問題,
JavaScript 本身就是延展性高的語言,
但由 Client 再拋給 Server 時,
Json.Net 將 JSON 反序列成物件時,
問題來了!
ViewModel.DataModel 只會被反序列化成 BaseModel ,
其他資料全掉光了,
傷腦筋啦! 該如何是好呢?
Solution:
基本概念是靠實作 CustomCreationConverterpublic interface IPerson { string FirstName { get; set; } string LastName { get; set; } DateTime BirthDate { get; set; } } public class Employee : IPerson { public string FirstName { get; set; } public string LastName { get; set; } public DateTime BirthDate { get; set; } public string Department { get; set; } public string JobTitle { get; set; } } public class PersonConverter : CustomCreationConverter{ public override IPerson Create(Type objectType) { return new Employee(); } }
發現有善心人士也遇到此問題,並公開解法
覆寫 JsonConverter,擴充 Create 方法
如下: ( 參考 )
public abstract class JsonCreationConverter: JsonConverter { protected abstract T Create(Type objectType, JObject jsonObject); public override bool CanConvert(Type objectType) { return typeof(T).IsAssignableFrom(objectType); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var jsonObject = JObject.Load(reader); var target = Create(objectType, jsonObject); serializer.Populate(jsonObject.CreateReader(), target); return target; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } }
再自訂 Json.Net Conveter,並依物件的 property 回覆類別,如下
public class ModelConverter : JsonCreationConverter { protected override BaseModel Create(Type objectType, JObject jsonObject) { if (jsonObject["Name"] != null) { return new ChildAModel(); } else if (jsonObject["SomeProperty1"] != null) { return new ChildBModel(); } else { return new BaseModel(); } } }
最後反序列化的使用方式,如下:
var deserializedModel = JsonConvert.DeserializeObject<BaseModel>(json, new ModelConverter ());
以上!