Search code examples
c#jsonjson.netdeserialization

Storing original JSON string in deserialised JSON.NET objects


This is basically a follow-on to the question Newtonsoft Object → Get JSON string .

I have an object that looks like this:

[JsonConverter(typeof(MessageConverter))]
public class Message
{
    public Message(string original)
    {
        this.Original = original;
    }

    public string Type { get; set; }

    public string Original { get; set; }
}

My requirement is to store the original JSON string as part of the object when I initialise it. I have been able to (partially) successfully achieve this using a custom JsonConverter and then basically doing something like this in the JsonConverter:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    if (reader.TokenType == Newtonsoft.Json.JsonToken.Null)
        return null;

    JObject obj = JObject.Load(reader);
    return new Message(obj.ToString(Formatting.None))
    {
        Type = obj["type"].ToString()
    };
}

However the problem I run into is when I try to inherit from Message with something like

public class CustomMessage : Message
{
    public string Prop1 { get; set; }
}

For obvious reasons my code fails because it tries to return a new Message() not a new CustomMessage().

So short of implementing a big if statement with all my sub-types and manually binding using something like JObject["prop"].ToObject<T>() how can I successfully populate the Original property while still binding all my sub-type values using the default deserialisation?

NOTE: The reason this is being done is because the original message might contain data that isn't actually being bound so I can't just add a property which serialises the object as it stands.


Solution

  • I'm leaving the question open in the hope that someone comes up with a better answer but I've temporarily used the following solution to resolve my problem.

    public static class MessageExtensions
    {
        public static T Deserialize<T>(this string message) where T : Message
        {
            T instance = Activator.CreateInstance<T>();
            instance.Original = message;
            JsonConvert.PopulateObject(message, instance);
            return instance;
        }
    }