2014-12-17 8 views
5

Ho una classe annotata con gli attributi DataContract e DataMember. Alcuni membri sono contrassegnati come DataMember(IsRequired = true). Quando serializzo le istanze sul filo da Json.NET e i membri degli oggetti richiesti hanno un valore nullo, i loro valori serializzati mancano nell'output (che è apparentemente equivalente a null in JSON). Sto bene con quello.Come deserializzare una proprietà mancante su un valore predefinito in Json.NET?

Ho creato una sorta di servizio "echo" che restituisce i dati inviati come risposta. Quindi questo servizio riceve il JSON con membri mancanti (o membri nulli a seconda di come lo si guarda), e quindi lo rimanda direttamente al mio client Json.NET. Il JSON sul cavo ha lo stesso aspetto in entrambe le direzioni visto da Fiddler (uno sniffer proxy). Fin qui tutto bene.

Quando il mittente originale Json.NET riceve la risposta JSON per deserializzare esso, il serializzatore genera un'eccezione di non trovare membri richiesti nel payload JSON:

Required property 'IAmRequired' not found in JSON. Path ''. 

Questo è un peccato, come il serializzatore è quindi non è in grado di deserializzare i dati che aveva precedentemente serializzato senza problemi.

In mancanza di modifica della classe DataContract per rendere il membro non richiesto (cosa che non desidero fare per una serie di motivi), esiste un modo per rendere deserializzato Json.NET ai membri mancanti ai valori predefiniti come null?

Ecco il mio codice deserializzazione:

HasRequired h = null; 
JObject json = response as JObject; // hand waving here 
try 
{ 
    JsonSerializer ser = new JsonSerializer(); 
    ser.MissingMemberHandling = MissingMemberHandling.Ignore; // doesn't seem to help 
    ser.DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate; // doesn't seem to help 
    ser.NullValueHandling = NullValueHandling.Include; // doesn't seem to help 
    h = json.ToObject<HasRequired>(ser); 
} 
catch (Exception ex) 
{ 
    // bummer, missing required members still 
} 
+0

Attendere, in modo da avere i membri indicati come necessari ma in realtà non sono obbligatori? –

+0

Sono richiesti ... ma solo per soddisfare alcune regole ottuse per DataContractSerializer per essere in grado di gestire la serializzazione per WCF (per un binding SOAP) e non avere i tipi di aspetto orribili per i client. So cosa stai dicendo; se non fosse per il serializzatore DC, sarebbero facoltativi. Per la fine della serializzazione SOAP, che ho cercato di evitare di menzionare, gli oggetti sono serializzati come istanze null XML (vengono inviati esplicitamente come null). – Greg

+0

Capisco. Ho aggiunto una risposta che dovrebbe aiutarti. –

risposta

0

Questo appare come un vero e proprio verruca sul mio codice, e deve essere ripetuta per ogni membro nullable-ma-richiesta, ma funziona, e sembra aggiungere trascurabili spese generali. Ho aggiunto questo appena prima del blocco try nel mio frammento originale:

JToken maybeHasIt = null; 
if (!json.TryGetValue("IAmRequired", StringComparison.InvariantCultureIgnoreCase, out maybeHasIt)) 
{ 
    json.Add("IAmRequired", null); 
} 
3

Se hai oggetti selezionati con [DataMember(Required = true)] e si desidera ignorare il comportamento richiesto, ci sono un paio di cose che si possono fare:

  1. È possibile contrassegnare le stesse proprietà con [JsonProperty(Required = Required.Default)]. Funziona perché [JsonProperty] ha la precedenza su [DataMember] in Json.Net.

    [DataContract] 
    public class HasRequired 
    { 
        [DataMember(Required = true)] 
        [JsonProperty(Required = Required.Default)] 
        public string IAmRequired { get; set; } 
    } 
    
  2. In alternativa, è possibile creare un ContractResolver personalizzato che imposta a livello di codice Required = Required.Default su ogni proprietà.

    class CustomResolver : DefaultContractResolver 
    { 
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 
        { 
         JsonProperty prop = base.CreateProperty(member, memberSerialization); 
         prop.Required = Required.Default; 
         return prop; 
        } 
    } 
    

    Per utilizzare il resolver, è sufficiente impostare la proprietà ContractResolver sulla serializzatore per una nuova istanza del resolver personalizzato:

    JsonSerializer ser = new JsonSerializer(); 
    ser = new CustomResolver(); 
    
Problemi correlati