我的服务器响应包含一组已知和未知的属性。对于已知的,我创建了一个DTO类,其中包含每个属性的成员。未知属性应放在使用[ExtensionData]
属性注释的字典中:
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class Dto
{
[JsonExtensionData]
private readonly Dictionary<string, object> unknownProperties = new Dictionary<string, object>();
public IDictionary<string, object> UnknownProperties
{
get
{
return new ReadOnlyDictionary<string, object>(this.unknownProperties);
}
}
[JsonProperty(Required = Required.Default, PropertyName = "KNOWN_PROPERTY")]
public string KnownProperty { get; private set; }
}
允许 Null
作为KnownProperty
的值。如果我尝试反序列化包含KNOWN_PROPERTY : null
的JSON对象,如果我使用UnknownProperties
配置序列化程序,则此属性也包含在字典NullValueHandling.Ignore
中。即使KNOWN_PROPERTY
:
static void Main(string[] args)
{
string jsonString = @"{
KNOWN_PROPERTY : null,
UNKNOWN_PROPERTY : null
}";
JsonSerializer serializer = JsonSerializer.CreateDefault(new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore
});
using (var textReader = new StringReader(jsonString))
{
Dto dto = serializer.Deserialize<Dto>(new JsonTextReader(textReader));
foreach (var pair in dto.UnknownProperties)
{
Console.WriteLine("{0}: {1}", pair.Key, pair.Value == null ? "null" : pair.Value.ToString());
}
}
}
输出:
KNOWN_PROPERTY : null
UNKNOWN_PROPERTY : null
如果我使用NullValueHandling.Include
配置序列化程序或在JSON字符串中为KNOWN_PROPERTY
设置值,则字典仅按预期包含UNKNOWN_PROPERTY
。
据我所知[ExtensionData]
如果将NullValueHandling
设置为忽略,则无法正常工作,因为documentation表示仅在未找到匹配的类成员时才使用扩展名。
我看到的行为是什么意思?我可以做些什么来避免这种情况吗?由于我不想将空值发送到服务器,因此我想坚持使用当前设置的NullValueHandling
。
我正在使用Json.NET 8.0.2
答案 0 :(得分:5)
<强>更新强>
在JsonExtensionData should not include the null values that are real object properties. #1719中报告并在提交e079301中修复。修复程序应该包含在11.0.2之后的Json.NET的下一个版本中。
原始答案
确认 - 在JsonSerializerInternalReader.PopulateObject(object, JsonReader, JsonObjectContract, JsonProperty, string)
中有以下逻辑:
first-class
如果要忽略属性,则意图似乎是将值放入扩展数据中,但如果值将被忽略 - 一个略有不同的概念。我同意这可能是一个错误。您可能需要report it。
有一种解决方法。 Json.NET有两个属性,这些属性会影响null / default值的序列化方式:
NullValueHandling
。指定在序列化和反序列化对象时包含或忽略空值。值为// set extension data if property is ignored or readonly
if (!SetPropertyValue(property, propertyConverter, contract, member, reader, newObject))
{
SetExtensionData(contract, member, reader, memberName, newObject);
}
和Include
。
DefaultValueHandling
。这有更复杂的语义:
Ignore
:在序列化对象时包括成员值与成员的默认值相同的成员。包含的成员将写入JSON。反序列化时没有效果。Include
:在序列化对象时忽略成员值与成员的默认值相同的成员,这样就不会写入JSON。此选项将忽略所有默认值(例如,对象和可空类型为null;对于整数,小数和浮点数为0;对于布尔值为false)。Ignore
:在反序列化时,具有默认值但没有JSON的成员将设置为其默认值。 Populate
:在序列化对象时忽略成员值与成员的默认值相同的成员,并在反序列化时将成员设置为默认值。 那么,这些重叠设置如何相互作用?事实证明,Json.NET同时检查它们:如果两个设置都一致则序列化,如果两个设置都令人满意则反序列化。并且IgnoreAndPopulate
似乎可以执行您想要的操作 - 它在序列化时省略了空值,但在反序列化时读取并设置它们(如果存在)。
因此,我能够通过以下DefaultValueHandling.IgnoreAndPopulate
得到您想要的行为:
JsonProperty
原型fiddle。