NewtonSoft JsonConvert - 反序列化JSON对象,看起来像{“@nil”:“真正的”}
问题描述:
我试图反序列化由REST服务返回以下JSON:NewtonSoft JsonConvert - 反序列化JSON对象,看起来像{“@nil”:“真正的”}
[{
"Vehicle": {
"Id": "1",
"RenewalDate": {
"@nil": "true"
}
}}]
服务似乎翻译XML到JSON,因此XML nil作为JSON字符串的一部分包含在内。
请让我知道如何在Newtonsoft反序列化方法中处理这个问题?
如果更新日期包含在字符串中,反序列化工作正常。
答
在没有你的问题的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。
当原始XML中不是'nil'时,'''RenewalDate''的值是什么?你试图将JSON反序列化为什么样的c#模型?如果你只是做'JToken.Parse(jsonString)'它应该可以正常工作,所以请分享你的目标模型的反序列化失败。 – dbc
这个[mcve]有没有机会?如果您向我们展示了迄今为止所做的工作以及确切的失败位置,我们更有可能为您提供可实际使用的解决方案。见[问]和https://codeblog.jonskeet.uk/2010/08/29/writing-the-perfect-question/。 – dbc