NewtonSoft JsonConvert - 反序列化一个看起来像{“@ nil”的JSON对象:“true”}

时间:2017-07-15 10:43:08

标签: json json.net

我正在尝试反序列化休息服务返回的以下JSON:

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

该服务似乎将XML转换为JSON,因此XML nil作为JSON字符串的一部分包含在内。

请告诉我如何在Newtonsoft反序列化方法中处理此问题?

如果字符串中包含续订日期,则反序列化可以正常工作。

1 个答案:

答案 0 :(得分:2)

如果没有问题的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值不是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; } } 值,而是包含已翻译的xsi:nil="true"属性的对象。

解决此问题的一种方法是引入以下custom JsonConverter

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

然后按如下方式反序列化:

nil

工作.Net fiddle

另一种选择是将JSON加载到JToken层次结构中,用null个JSON值替换从WasNilXmlElement() XML元素转换的所有JSON对象,然后最终反序列化到您的模型。首先,介绍以下扩展方法,该方法使用第一个解决方案中的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

此解决方案避免了对每个可空类型List<<AnyClass>>的需要。工作fiddle #2