2017-04-14 99 views
0

Json.Net是不是將它收到的對象反序列化爲我的Control類的正確衍生物。 (請參閱下面的問題說明,同時請注意,我覺得這是解釋問題所需的最小代碼量。提前感謝您審覈此問題。)Json.Net反序列化到C#派生類

我試圖序列化/反序列化將以下類(/)轉換爲JSON。

public class Page { 
    public Guid Id { get; set; } 
    public Guid CustomerId { get; set; } 
    public IList<Control> Controls { get; set; } 
} 

這裏是控制類:

public class Control : ControlBase 
{ 
    public override Enums.CsControlType CsControlType { get { return Enums.CsControlType.Base; } } 
} 

這裏是ControlBase抽象類:

public abstract class ControlBase 
{ 
    public Guid Id { get; set; } 

    public virtual Enums.CsControlType CsControlType { get; } 

    public Enums.ControlType Type { get; set; } 

    public string PropertyName { get; set; } 

    public IList<int> Width { get; set; } 

    public string FriendlyName { get; set; } 

    public string Description { get; set; } 
} 

而這裏是從控制導出的OptionsControl:

public class OptionsControl : Control 
{ 
    public override Enums.CsControlType CsControlType { get { return Enums.CsControlType.OptionsControl; } } 

    public IDictionary<string, string> Options; 
} 

當OptionsControl被序列化,JSON如下所示。請注意,Json.Net添加$type屬性,以便(據推測)它可以將控制反序列化到OptionsControl中。

   { 
       "options":{ 
        "TN":"TN" 
       }, 
       "csControlType":4, 
       "id":"00000000-0000-0000-0000-000000000000", 
       "type":4, 
       "propertyName":"addresses[0].state", 
       "width":[ 
        2, 
        2, 
        6 
       ], 
       "friendlyName":"State", 
       "description":null, 
       "$type":"MyApp.Infrastructure.Core.Models.UI.Controls.OptionsControl, MyApp.Infrastructure.Core" 
       } 

然而,當我嘗試反序列化頁(其包含基本控件和OptionsControls),所有控制被反序列化爲Control基和options屬性(其包括國家名單,上文)將被忽略。

這是我嘗試反序列化(和更新)我通過的WebAPI服務接收Page對象:

[HttpPut] 
    [ActionName("UpdatePage")] 
    public async Task<CommandResult> UpdatePageAsync([FromBody]Object page) 
    { 
     try 
     { 
      // Deserialize the page into the correct object 
      // When I Debug.WriteLine the page.ToString(), the page still has the $type property at this point (before it is deserialized). 
      var dsPage = return JsonConvert.DeserializeObject<Page>(page.ToString(), new JsonSerializerSettings 
      { 
       TypeNameHandling = TypeNameHandling.All 
      }); 

      // The dsPage passed in here does not have any OptionsControls. 
      // At this point, they have all been deserialized into the base Control, unfortunately. 
      return await _uiCommandFacade.UpdatePageAsync(dsPage, msg); 
     } 
     catch (Exception ex) 
     { 
      return new CommandResult() 
      { 
       ErrorType = ErrorType.ControllerError, 
       DeveloperMessage = $"Unable to update page", 
       Exception = ex 
      }; 
     } 
    } 

正如你所看到的,我使用TypeNameHandling.All(如文檔描述和在SO上多次提到)用於反序列化(就像我在序列化期間那樣,這是在JSON中生成$type屬性的原因)。但是,當我反序列化頁面對象時,頁面對象中的任何OptionsControl被反序列化爲常規基地Control s,因此Options屬性將被忽略(因此我的列表不會更新/丟棄)。

如何讓Json.Net正確地反序列化我的控件及其衍生產品?

回答

2

看起來問題可能是由於$type元數據屬性不是您的控件的JSON中的第一個屬性。通常,Json.Net需要這個屬性才能識別它。嘗試添加

MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead 

到您的設置反序列化時。這應該讓Json。Net在JSON中稍後查找$type屬性。

+0

先生,您是一位紳士和學者。 – Targaryen

+0

很高興能幫到你。 –

0

我想你應該在你的web-api啓動類中設置你的配置。

嘗試在startup.cs文件類似

 GlobalConfiguration.Configuration.Formatters.Clear(); // or remove just the json one 

     var jsonformatter = new System.Net.Http.Formatting.JsonMediaTypeFormatter() 
     { 
      SerializerSettings = new Newtonsoft.Json.JsonSerializerSettings() 
      { 
       // all your configurations 
       TypeNameHandling = Newtonsoft.Json.TypeNameHandling.All 
      } 
     }; 

     GlobalConfiguration.Configuration.Formatters.Add(jsonformatter); 

我認爲你正在失去的信息,因爲你在方法的反序列化對象的項目(頁),然後你再序列化通過調用頁面.tostring()方法,然後使用序列化程序屬性再次反序列化它。