2017-08-11 4 views
1

J'ai un message JSON à désérialiser avec une propriété de chaîne contenant le JSON d'un autre objet. Je les classes suivantesJSON.NET désérialise l'objet JSON stocké en tant que propriété

public class Envelope 
{ 
    public string Type { get; set; } 
    public Message InnerMessage { get; set; } 
} 

public class Message 
{ 
    public string From { get; set; } 
    public string To { get; set; } 
    public string Body { get; set; } 
} 

le message que je reçois JSON est dans ce format:

{ 
    Type : "send", 
    InnerMessage : "{ From: \"sender\", To: \"receiver\", Body: \"test\" }" 
} 

Notez que InnerMessage contient la sérialisation de la classe Message, pas le JSON de la classe.

Si je conserve le type de propriété InnerMessage à Message, la désérialisation JSON.NET standard échoue.

Si je change les InnerMessage à string, les travaux de sérialisation, mais après que je dois désérialiser à nouveau le contenu de InnerMessage à Message classe:

Envelope envelope = JsonConvert.DeserializeObject<Envelope>(jsonMessage); 
Message innerMessage = JsonConvert.DeserializeObject<Envelope>(envelope.InnerMessage); 

Il y a une certaine façon de garder la propriété InnerMessage de Envelope à Message et dire à JSON.NET de traiter la valeur de chaîne à désérialiser automatiquement?

+0

Comment êtes-vous sérialisation votre objet? Quand j'utilise 'JsonConvert.SerializeObject (enveloppe)', j'obtiens une sortie Json différente de celle que vous avez. –

+0

Je reçois le JSON d'un webservice, j'ai juste besoin de le désérialiser aux classes que j'ai créées –

+0

Gotcha, on dirait que @SirRufo a la réponse à votre recherche –

Répondre

2

Vous avez besoin d'une mesure JsonConverter

class StringTypeConverter : Newtonsoft.Json.JsonConverter 
{ 
    public override bool CanRead => true; 
    public override bool CanWrite => true; 

    public override bool CanConvert(Type objectType) 
    { 
     return true; 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     string json = (string)reader.Value; 
     var result = JsonConvert.DeserializeObject(json, objectType); 
     return result; 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var json = JsonConvert.SerializeObject(value); 
     serializer.Serialize(writer, json); 
    } 
} 

et ajoutez un JsonConverterAttribute à la propriété InnerMessage

public class Envelope 
{ 
    public string Type { get; set; } 
    [Newtonsoft.Json.JsonConverter(typeof(StringTypeConverter))] 
    public Message InnerMessage { get; set; } 
} 

public class Message 
{ 
    public string From { get; set; } 
    public string To { get; set; } 
    public string Body { get; set; } 
} 

et maintenant vous pouvez linéariser/désérialiser la classe Envelope avec

var envelope = JsonConvert.DeserializeObject<Envelope>(jsonMessage); 
+0

merci, votre solution semble plus propre que l'autre, demain je vais le tester –

+0

votre solution fonctionne parfaitement, merci encore –

2

Vous pouvez le faire avec un convertisseur personnalisé. Par exemple:

public class EnvelopeConverter : JsonConverter 
{ 
    public override void WriteJson(JsonWriter writer, object value, 
     JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, 
     object existingValue, JsonSerializer serializer) 
    { 
     var envelope = JObject.Load(reader); 

     var type = envelope["Type"].ToString(); 
     var message = JsonConvert.DeserializeObject<Message>(
      envelope["InnerMessage"].ToString()); 

     return new Envelope 
     { 
      Type = type, 
      InnerMessage = message 
     }; 
    } 

    public override bool CanRead 
    { 
     get { return true; } 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return true; 
    } 
} 

Et l'utiliser comme ceci:

Envelope envelope = JsonConvert.DeserializeObject<Envelope>(
    jsonMessage, new EnvelopeConverter()); 
+0

merci pour votre réponse, mais personnellement je préfère celle de Sir Rufo comme je peut s'appliquer à la propriété spécifique et non à la classe –