如何强制Newtonsoft Json序列化所有属性? ("指定"属性的奇怪行为)

时间:2016-08-30 09:13:40

标签: c# serialization json.net

研究员, 我在Newtonsoft.Json中遇到过一个奇怪的行为。

当我尝试序列化一个看起来像这样的对象时:

public class DMSDocWorkflowI
{
    [JsonProperty("DMSDocWorkflowIResult")]
    public bool DMSDocWorkflowIResult { get; set; }

    [JsonProperty("DMSDocWorkflowIResultSpecified")]
    public bool DMSDocWorkflowIResultSpecified { get; set; }
}

使用这个简单的调用,没有自定义的转换器/绑定器/合约解析器:

var testObject = new DMSDocWorkflowI();
var json = JsonConvert.SerializeObject(testObject, Formatting.Indented);

或甚至JToken.FromObject(...)我总是只获得一个属性:

{
   "DMSDocWorkflowIResultSpecified": false
}

当我附加跟踪编写器时,它只捕获这个:

[0]: "2016-08-30T11:06:27.779 Info Started serializing *****DMSDocWorkflowI. Path ''."
[1]: "2016-08-30T11:06:27.779 Verbose IsSpecified result for property 'DMSDocWorkflowIResult' on *****DMSDocWorkflowI: False. Path ''."
[2]: "2016-08-30T11:06:27.779 Info Finished serializing *****.DMSDocWorkflowI. Path ''."
[3]: "2016-08-30T11:06:27.780 Verbose Serialized JSON: \r\n{\r\n  \"DMSDocWorkflowIResultSpecified\": false\r\n}"

所以似乎Newtonsoft.Json对待这个" Specified"财产有些神奇。 我能把它关掉吗? 我在生成的JSON中需要这两个属性,并且具有这些名称。

1 个答案:

答案 0 :(得分:10)

Json.NET 4.0.1 release notes新功能中添加了XmlSerializer样式指定的属性支持,提及了非常这一行为。 XmlSerializer功能依次在MinOccurs Attribute Binding Support中描述:

  

[对于可选字段] Xsd.exe生成类型为bool的公共字段,其名称为附加了Specified的元素字段名称。例如,如果元素字段的名称是startDate,则bool字段的名称将变为startDateSpecified。将对象序列化为XML时,XmlSerializer类会检查bool字段的值以确定是否编写该元素。

我觉得这个功能应该记录在here,但事实并非如此。您可能希望使用Newtonsoft open a documentation issue

由于您不想要此行为,如果您使用的是Json.NET 11.0.1 or later,则可以通过实例化自己的DefaultContractResolver并设置DefaultContractResolver.IgnoreIsSpecifiedMembers = true来禁用所有类:

public static class JsonContractResolvers
{
    // As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons.
    // http://www.newtonsoft.com/json/help/html/ContractResolver.htm
    // http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm
    // "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance."

    public static readonly DefaultContractResolver IgnoreIsSpecifiedMembersResolver =
        new DefaultContractResolver { IgnoreIsSpecifiedMembers = true };
}

然后将其传递给JsonConvert,如下所示:

var settings = new JsonSerializerSettings { ContractResolver = JsonContractResolvers.IgnoreIsSpecifiedMembersResolver };
var json = JsonConvert.SerializeObject(testObject, Formatting.Indented, settings);

或创建JToken执行:

var jToken = JToken.FromObject(testObject, JsonSerializer.CreateDefault(settings));

如果您使用的是早期版本,则需要创建并缓存custom contract resolver

public static class JsonContractResolvers
{
    // As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons.
    // http://www.newtonsoft.com/json/help/html/ContractResolver.htm
    // http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm
    // "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance."

    public static readonly DefaultContractResolver IgnoreIsSpecifiedMembersResolver =
        new IgnoreSpecifiedContractResolver();
}

internal class IgnoreSpecifiedContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        property.GetIsSpecified = null;
        property.SetIsSpecified = null;
        return property;
    }
}