Configurare JSON.NET per ignorare gli attributi DataContract / DataMember

Stiamo incontrando una situazione in un progetto MVC3 con i serializzatori Microsoft JSON e JSON.NET.

Tutti sanno che i DateTime sono fondamentalmente rotti nei serializzatori di Microsoft, quindi siamo passati a JSON.NET per evitare questo problema. Funziona alla grande, tranne che alcune delle classi che stiamo cercando di serializzare sono POCO con attributi DataContract / DataMember. Sono definiti in un assembly a cui viene fatto riferimento in più punti. Inoltre, hanno altre proprietà di visualizzazione che non sono contrassegnate come DataMembers per l’efficienza. Ad esempio, 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; } } } 

Quando questo cliente viene passato su WCF, il lato client può fare riferimento a tale assembly e utilizzare FullName, ma quando serializzato con JSON.NET vede che FullName non è un [DataMember] e non lo serializza. Esiste un’opzione da passare a JSON.NET per dirgli di ignorare il fatto che una class ha applicato l’attributo [DataContract] ?

Nota: l’ utilizzo di JavaScriptSerializer in .NET funziona correttamente con la proprietà FullName, ma DateTimes è danneggiato. Ho bisogno che JSON.NET ignori il fatto che questa class abbia gli attributi DataContract / DataMember e faccia semplicemente la serializzazione standard del campo pubblico come se non esistesse.

Basta usare l’attributo OptOut di Json.Net. Avrà la precedenza su DataContract.

 [DataContract] [JsonObject(MemberSerialization.OptOut)] 

Come ha detto Amry, puoi usare il tuo IContractResolver.

Purtroppo la soluzione fornita da Amry non ha funzionato per me, di seguito è la soluzione che sono riuscito a ottenere lavorando:

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

Ci sono alcune righe commentate, queste non sono necessarie per far funzionare la mia soluzione, ma non si sa mai!

Questo ha lo stesso utilizzo della soluzione di Amry:

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

Spero che questo ti aiuti!

Stavo avendo un problema quasi correlato a quello che stai avendo, e sono riuscito a trovare una soluzione passando attraverso i codici di Json.NET. Quindi potrebbe non essere la soluzione migliore, ma funziona per me.

Per fare ciò, è necessario implementare il proprio IContractResolver . Un’implementazione eccessivamente semplificata di questo per includere tutti i parametri e ignora tutti gli attributi (non solo DataContract ma anche le altre regole di Json.NET incorporate, quindi qualsiasi opzione impostata che dovrebbe in origine riguardare la selezione dei membri viene ora sovrascritta da questo codice ):

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

E qui arriva l’esempio di utilizzo del codice:

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

Se si desidera ignorare la presenza di DataContractAttribute per tutti i tipi senza dover aggiungere ulteriori attributi, un risolutore di contratto personalizzato è la soluzione corretta. Tuttavia, a partire da JSON.NET 9.0.1 il risolutore di Amry non funziona più. Il risolutore di Doolali funziona ma ha l’ulteriore effetto collaterale di serializzare tutte le proprietà pubbliche incluse quelle contrassegnate con [JsonIgnore] . Se si richiede un risolutore del contratto che ignori solo la presenza di DataContractAttribute ma si comporti in altro modo come il resolver del contratto predefinito, è ansible utilizzare quanto segue:

 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()).FirstOrDefault(a => a != null); var jsonObjectAttribute = type.GetCustomAttribute(); if (dataContractAttribute != null && jsonObjectAttribute == null) memberSerialization = MemberSerialization.OptOut; } return memberSerialization; } protected override IList 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 BaseTypesAndSelf(this Type type) { while (type != null) { yield return type; type = type.BaseType; } } } 

Si consiglia di memorizzare nella cache il risolutore del contratto per ottenere prestazioni ottimali .

Secondo la documentazione di [DataMember] attributi [DataMember] vengono ignorati se le proprietà sono annotate anche con attributi specifici di Json.NET (come [JsonProperty] ) [JsonProperty] la documentazione degli attributi di serializzazione per i dettagli:

Gli attributi di Json.NET prendono presunzione rispetto agli attributi di serializzazione .NET standard, ad esempio se sia JsonPropertyAttribute che DataMemberAttribute sono presenti su una proprietà ed entrambi personalizzano il nome, verrà utilizzato il nome da JsonPropertyAttribute.

La documentazione copre solo la proprietà del nome, ma per la mia esperienza l’attributo [JsonProperty] anche completamente le impostazioni delle ombre eseguite dall’attributo [DataMember] . Quindi, se è fattibile per il tuo caso, aggiungi anche attributi Json.NET alle proprietà per le quali l’annotazione [DataMember] deve essere ignorata.

Hai provato questo?

IgnoreDataMemberAttribute