2017-07-15 47 views
0

我試圖反序列化由REST服務返回以下JSON:NewtonSoft JsonConvert - 反序列化JSON對象,看起來像{「@nil」:「真正的」}

[{ 
"Vehicle": { 
    "Id": "1", 
    "RenewalDate": { 
    "@nil": "true" 
    }  
}}] 

服務似乎翻譯XML到JSON,因此XML nil作爲JSON字符串的一部分包含在內。

請讓我知道如何在Newtonsoft反序列化方法中處理這個問題?

如果更新日期包含在字符串中,反序列化工作正常。

+0

當原始XML中不是'nil'時,'''RenewalDate''的值是什麼?你試圖將JSON反序列化爲什麼樣的c#模型?如果你只是做'JToken.Parse(jsonString)'它應該可以正常工作,所以請分享你的目標模型的反序列化失敗。 – dbc

+0

這個[mcve]有沒有機會?如果您向我們展示了迄今爲止所做的工作以及確切的失敗位置,我們更有可能爲您提供可實際使用的解決方案。見[問]和https://codeblog.jonskeet.uk/2010/08/29/writing-the-perfect-question/。 – dbc

回答

1

在沒有你的問題的Minimal, Complete, and Verifiable example的,我會假設你正試圖反序列化類的列表看起來像這樣:

public class Vehicle 
{ 
    public string Id { get; set; } 

    [XmlElement(IsNullable = true)] 
    public DateTime? RenewalDate { get; set; } 
} 

public class RootObject 
{ 
    public Vehicle Vehicle { get; set; } 
} 

而且,反序列化失敗的屬性"RenewalDate",因爲不存在JSON中出現的null值,因此存在包含翻譯的xsi:nil="true"屬性的對象。要解決這個

一種方式是引進以下custom JsonConverter

public class NullableStructConverter<T> : JsonConverter where T : struct 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(Nullable<T>); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var underlyingType = Nullable.GetUnderlyingType(objectType); 
     if (underlyingType == null) 
      throw new InvalidOperationException(string.Format("Type {0} is not nullable", objectType)); 
     var token = JToken.Load(reader); 
     if (token.Type == JTokenType.Null) 
      return null; 
     if (token.WasNilXmlElement()) 
      return null; 
     return token.ToObject(underlyingType, serializer); 
    } 

    public override bool CanWrite { get { return false; } } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

public static partial class JTokenExtensions 
{ 
    public static bool WasNilXmlElement(this JToken token) 
    { 
     if (token == null) 
      return true; 
     if (token.Type == JTokenType.Null) 
      return true; 
     var obj = token as JObject; 
     if (obj != null) 
     { 
      // Check if all properties were translated from XML attributes 
      // and one was translated from xsi:nil = true 
      // There might be namespaces present as well, e.g. 
      // "@xmlns:p3": "http://www.w3.org/2001/XMLSchema-instance" 
      if (obj.Properties().All(p => p.Name.StartsWith("@")) 
       && obj.Properties().Any(p => p.Name == "@nil" || p.Name.EndsWith(":nil") && p.Value.ToString() == "true")) 
       return true; 
     } 
     return false; 
    } 
} 

然後反序列化如下:

var settings = new JsonSerializerSettings 
{ 
    Converters = { new NullableStructConverter<DateTime>() } 
    // Whatever other settings you require. 
}; 
var root = JsonConvert.DeserializeObject<RootObject[]>(json, settings); 

工作.Net fiddle

另一種選擇是將JSON裝載到JToken層次結構,取代了從null JSON值nil XML元素翻譯所有JSON對象,然後最後反序列化到模型。首先,介紹其使用WasNilXmlElement()從第一溶液中以下擴展方法:

public static partial class JTokenExtensions 
{ 
    public static JToken ReplaceNilXmlElementObjectsWithNull(this JToken root) 
    { 
     var rootContainer = root as JContainer; 
     if (rootContainer == null) 
      return root; 
     var list = rootContainer.DescendantsAndSelf() 
      .OfType<JObject>() 
      .Where(o => o.WasNilXmlElement()) 
      .ToList(); 
     foreach (var obj in list) 
     { 
      var replacement = JValue.CreateNull(); 
      if (obj.Parent != null) 
       obj.Replace(replacement); 
      if (root == obj) 
       root = replacement; 
     } 
     return root; 
    } 
} 

和反序列化如下:

var settings = new JsonSerializerSettings 
{ 
    // Whatever settings you require. 
}; 
var root = JsonConvert.DeserializeObject<JToken>(json, settings) 
    .ReplaceNilXmlElementObjectsWithNull() 
    .ToObject<RootObject[]>(JsonSerializer.CreateDefault(settings)); 

該溶液避免了對JsonConverter每個空類型的需要。工作fiddle #2