2012-06-15 24 views
26

Nos encontramos en una situación en un proyecto de MVC3 con los serializadores JSON de Microsoft y JSON.NET.Configure JSON.NET para ignorar los atributos de DataContract/DataMember

Todo el mundo sabe que los DateTime están básicamente rotos en los serializadores de Microsoft, así que cambiamos a JSON.NET para evitar este problema. Eso funciona muy bien, excepto que algunas de las clases que intentamos serializar son POCO con atributos DataContract/DataMember. Se definen en un conjunto al que se hace referencia en múltiples lugares. Además, tienen algunas otras propiedades de visualización que no están marcadas como DataMembers para mayor eficiencia. Por ejemplo, un cliente

[DataContract] 
public class Customer 
{ 
    [DataMember] 
    public string FirstName { get; set;} 
    [DataMember] 
    public string LastName { get; set;} 
    public string FullName 
    { 
     get 
     { return FirstName + " " + LastName; } 
    } 

} 

Cuando este cliente se pasa sobre el lado del cliente WCF puede hacer referencia a que el montaje y el uso de la NombreCompleto muy bien, pero cuando serializado con JSON.NET ve que no es un NombreCompleto [DataMember] y no lo serializa ¿Hay una opción para pasar a JSON.NET para decirle que ignore el hecho de que una clase tiene el atributo [DataContract] aplicado?

Nota: Usar el JavaScriptSerializer en .NET funciona bien para la propiedad FullName, pero los DateTimes están rotos. Necesito que JSON.NET ignore el hecho de que esta clase tiene atributos DataContract/DataMember y simplemente hace la serialización estándar del campo público como lo haría si no estuvieran allí.

+1

¿Resolvió esto? Estoy teniendo exactamente el mismo problema y necesito encontrar una resolución –

+2

Terminé agregando el atributo JsonProperty para Json.Net – Nick

Respuesta

0

¿Has probado esto?

IgnoreDataAttribute

+2

Quiero hacer lo contrario de ignorar el campo, quiero que el campo se incluya al serializar usando JSON.NET – Nick

13

estaba teniendo un problema casi relacionado con lo que tienes, y logró encontrar una solución pasando a través de los códigos de Json.NET. Por lo tanto, puede que no sea la mejor solución, pero funciona para mí. Para hacer esto, necesita implementar su propio IContractResolver. Una implementación demasiado simplificada de eso para incluir todos los parámetros e ignora todos los atributos (no solo DataContract sino también otras reglas incorporadas de Json.NET, así que cualquier opción que establezca que debería afectar originalmente a la selección de miembros ahora está siendo reemplazada por este código):

class AllPropertiesResolver : DefaultContractResolver 
{ 
    protected override List<MemberInfo> GetSerializableMembers(Type objectType) 
    { 
     return objectType.GetProperties() 
      .Where(p => p.GetIndexParameters().Length == 0) 
      .Cast<MemberInfo>() 
      .ToList(); 
    } 
} 

Y aquí viene el ejemplo de uso código:

var json = JsonConvert.SerializeObject(result, new JsonSerializerSettings { 
    ContractResolver = new AllPropertiesResolver() 
}); 
+1

Esto no funciona. – NielW

+2

Genial. Por qué no? ¿Qué no está funcionando? Ayúdanos a ayudarte – Cornelius

+0

Este enfoque no funcionó para mí tampoco Amry, ¿hay algo más que tengas que agregar para que funcione? – Scott

15

Como se ha dicho Amry puedas utiliza su propia IContractResolver.

Por desgracia, la solución proporcionada por Amry no funcionó para mí, a continuación es la solución que he conseguido trabajo:

public class AllPropertiesResolver : DefaultContractResolver 
{ 
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 
    { 
     JsonProperty property = base.CreateProperty(member, memberSerialization); 

     //property.HasMemberAttribute = true; 
     property.Ignored = false; 

     //property.ShouldSerialize = instance => 
     //{ 
     // return true; 
     //}; 

     return property; 
    } 
} 

No se comentan algunas líneas, éstos gustaban no obligados a hacer mi trabajo de solución, pero nunca se sabe!

Esto tiene el mismo uso que la solución de Amry:

var json = JsonConvert.SerializeObject(result, new JsonSerializerSettings { 
    ContractResolver = new AllPropertiesResolver() 
}); 

espero que esto ayude!

6

Según la documentación de Json.NET [DataMember], los atributos se ignoran si las propiedades también están anotadas con atributos específicos de Json.NET (como [JsonProperty]).Ver el Serialization Attributes documentation para más detalles:

Json.NET atributos toman presidencia sobre los atributos de NET serialización estándar, por ejemplo, si tanto JsonPropertyAttribute como DataMemberAttribute están presentes en una propiedad y ambos personalizan el nombre, se usará el nombre de JsonPropertyAttribute.

La documentación sólo se explica la propiedad de nombre, pero por mi experiencia el atributo [JsonProperty] también sombras completamente las configuraciones realizadas por el atributo [DataMember]. Por lo tanto, si es factible para su caso, también agregue atributos Json.NET a las propiedades para las cuales se debe ignorar la anotación [DataMember].

11

Simplemente use el atributo OptOut de Json.Net. Tendrá prioridad sobre DataContract.

[DataContract] 
[JsonObject(MemberSerialization.OptOut)] 
5

Si desea ignorar la presencia de DataContractAttribute para todo tipo sin tener que añadir atributos adicionales, a continuación, un custom contract resolver es la solución correcta. Sin embargo, a partir de Json.NET 9.0.1 Amry's resolver ya no funciona. Doolali's resolver funciona pero tiene el efecto secundario adicional de serializar todas las propiedades públicas, incluidas las marcadas con [JsonIgnore]. Si necesita una resolución de contrato que sólo se ignora la presencia de DataContractAttribute pero por lo demás se comporta como el solucionador de contrato por omisión, lo siguiente puede ser usado:

public class IgnoreDataContractContractResolver : DefaultContractResolver 
{ 
    static MemberSerialization RemoveDataContractAttributeMemberSerialization(Type type, MemberSerialization memberSerialization) 
    { 
     if (memberSerialization == MemberSerialization.OptIn) 
     { 
      type = Nullable.GetUnderlyingType(type) ?? type; 

      // Json.NET interprets DataContractAttribute as inherited despite the fact it is marked with Inherited = false 
      // https://json.codeplex.com/discussions/357850 
      // https://stackoverflow.com/questions/8555089/datacontract-and-inheritance 
      // https://github.com/JamesNK/Newtonsoft.Json/issues/603 
      // Thus we need to manually climb the type hierarchy to see if one is present. 

      var dataContractAttribute = type.BaseTypesAndSelf().Select(t => t.GetCustomAttribute<DataContractAttribute>()).FirstOrDefault(a => a != null); 
      var jsonObjectAttribute = type.GetCustomAttribute<JsonObjectAttribute>(); 

      if (dataContractAttribute != null && jsonObjectAttribute == null) 
       memberSerialization = MemberSerialization.OptOut; 
     } 
     return memberSerialization; 
    } 

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) 
    { 
     var properties = base.CreateProperties(type, RemoveDataContractAttributeMemberSerialization(type, memberSerialization)); 
     return properties; 
    } 

    protected override JsonObjectContract CreateObjectContract(Type objectType) 
    { 
     var contract = base.CreateObjectContract(objectType); 
     contract.MemberSerialization = RemoveDataContractAttributeMemberSerialization(objectType, contract.MemberSerialization); 
     return contract; 
    } 
} 

public static class TypeExtensions 
{ 
    public static IEnumerable<Type> BaseTypesAndSelf(this Type type) 
    { 
     while (type != null) 
     { 
      yield return type; 
      type = type.BaseType; 
     } 
    } 
} 

Es posible que desee cache the contract resolver for best performance.

+0

@HappyNomad - 'DefaultContractResolver' no proporciona una forma simple de insertar atributos. Anulo 'CreateProperties()' para pasar 'OptOut' - pero el valor de 'contract.MemberSerialization' todavía regresaba como' OptIn'. Como eso parecía inconsistente, elegí anular 'CreateObjectContract()' también. – dbc

+1

Buena solución, pero me di cuenta de que 'RemoveDataContractAttributeMemberSerialization 'se llama innecesariamente dos veces por tipo. Esto se debe a que 'base.CreateObjectContract' llama' CreateProperties'. Envié [un problema] (https://github.com/JamesNK/Newtonsoft.Json/issues/1024) a JSON.NET sobre esto. – HappyNomad

+1

Sí, lo noté inmediatamente después de publicar mi comentario y, por lo tanto, reescribí mi comentario. – HappyNomad

Cuestiones relacionadas