Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force Newtonsoft Json to serialize all properties? (Strange behavior with "Specified" property)

Fellow programmers, I've encountered a strange behavior in Newtonsoft.Json.

When I'm trying to serialize an object looking like this:

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

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

Using this simple call with no custom converters / binders / contract resolvers:

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

or even with JToken.FromObject(...) I always get only one property:

{
   "DMSDocWorkflowIResultSpecified": false
}

When I attach the trace writer, it catches only this:

[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}"

So it seems Newtonsoft.Json treats this "Specified" property somewhat magically. Can I turn this off? I need both these properties in resulting JSON with exactly these names.

like image 776
Michael K. Sondej Avatar asked Aug 30 '16 09:08

Michael K. Sondej


1 Answers

This behavior is mentioned, very briefly, in the Json.NET 4.0.1 release notes: New feature - Added XmlSerializer style Specified property support. The XmlSerializer functionality is in turn described in MinOccurs Attribute Binding Support:

[For optional fields] Xsd.exe generates a public field of type bool whose name is the element field's name with Specified appended. For example, if the element field's name is startDate, the bool field's name becomes startDateSpecified. When serializing an object to XML, the XmlSerializer class checks the value of the bool field to determine whether to write the element.

I feel as though this functionality should be documented here, but is not. You might want to open a documentation issue with Newtonsoft.

Since you don't want this behavior, if you are using Json.NET 11.0.1 or later, you can disable it for all classes by instantiating your own DefaultContractResolver and settting DefaultContractResolver.IgnoreIsSpecifiedMembers = true:

public static class JsonContractResolvers
{
    // Newtonsoft recommends caching and reusing contract resolvers for best performance:
    // https://www.newtonsoft.com/json/help/html/Performance.htm#ReuseContractResolver
    // But be sure not to modify IgnoreIsSpecifiedMembers after the contract resolver is first used to generate a contract.

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

Then pass it to JsonConvert as follows:

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

Or to create a JToken do:

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

If you are using an earlier version, you will need to create and cache a custom contract resolver:

public static class JsonContractResolvers
{
    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;
    }
}
like image 94
dbc Avatar answered Nov 06 '22 01:11

dbc