Reputation: 15128
I have a JSON message to deserialize with a string property containing the JSON of another object. I have the following classes
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; }
}
the JSON message I receive is in this format:
{
Type : "send",
InnerMessage : "{ From: \"sender\", To: \"receiver\", Body: \"test\" }"
}
note that InnerMessage
contains the serialization of the Message
class, not the JSON of the class.
If I keep the type of InnerMessage
property to Message
, the standard JSON.NET deserialization fails.
If I change the InnerMessage
to string
, the serialization works but after I need to deserialize again the content of InnerMessage
to Message
class:
Envelope envelope = JsonConvert.DeserializeObject<Envelope>(jsonMessage);
Message innerMessage = JsonConvert.DeserializeObject<Envelope>(envelope.InnerMessage);
There is some way to keep the InnerMessage
property of Envelope
to Message
and tell JSON.NET to treat the string value to be deserialized automatically?
Upvotes: 3
Views: 9128
Reputation: 19096
You need a custom 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);
}
}
and add a JsonConverterAttribute
to the InnerMessage
property
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; }
}
and now you can serialize/deserialize the Envelope
class with
var envelope = JsonConvert.DeserializeObject<Envelope>( jsonMessage );
Upvotes: 5
Reputation: 118937
You can do this with a custom converter. For example:
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;
}
}
And use it like this:
Envelope envelope = JsonConvert.DeserializeObject<Envelope>(
jsonMessage, new EnvelopeConverter());
Upvotes: 3