¿Cómo forzar a Newtonsoft Json a serializar todas las propiedades? (Comportamiento extraño con la propiedad “Especificada”)

Compañeros progtwigdores, he encontrado un extraño comportamiento en Newtonsoft.Json.

Cuando estoy tratando de serializar un objeto con este aspecto:

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

Usando esta simple llamada sin convertidores / carpetas / resolvedores de contratos personalizados:

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

o incluso con JToken.FromObject(...) Siempre obtengo una sola propiedad:

 { "DMSDocWorkflowIResultSpecified": false } 

Cuando adjunto el rastreador, se captura solo esto:

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

Así que parece que Newtonsoft.Json trata esta propiedad “Especificada” de forma mágica. ¿Puedo apagar esto? Necesito ambas propiedades en JSON resultante con exactamente estos nombres.

Este comportamiento se menciona, muy brevemente, en las notas de la versión de Json.NET 4.0.1 : Nueva función – Compatibilidad con propiedades de estilo XmlSerializer añadido . La funcionalidad XmlSerializer se describe a su vez en MinOccurs Attribute Binding Support :

[Para los campos opcionales] Xsd.exe genera un campo público de tipo bool cuyo nombre es el nombre del campo del elemento con el anexo especificado. Por ejemplo, si el nombre del campo del elemento es startDate, el nombre del campo bool se convierte en startDateSpecified. Al serializar un objeto a XML, la clase XmlSerializer verifica el valor del campo bool para determinar si se debe escribir el elemento.

Siento que esta funcionalidad debería estar documentada aquí , pero no lo está. Es posible que desee abrir un problema de documentación con Newtonsoft.

Dado que no desea este comportamiento, si está utilizando Json.NET 11.0.1 o posterior , puede deshabilitarlo para todas las clases creando una instancia de su propio DefaultContractResolver y estableciendo 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 }; } 

Luego JsonConvert a JsonConvert siguiente manera:

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

O para crear un JToken do:

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

Si está utilizando una versión anterior, tendrá que crear y guardar en caché una resolución de contratos personalizada :

 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; } }