1

I'm getting JSON from a web hook where the type of the object is baked into the JSON itself, kind of like this:

Example of data that is of type "a":

{
    "type": "a",
    "name": "object name",
    "a_data": "something specific to type a"
}

And Example of data that is of type "b":

{
    "type": "b",
    "name": "another object name",
    "b_data": {
        "b_field1": "Something specific to type b",
        "b_field2": "Something else specific to type b"
    }

I am guaranteed that every payload will have a type and a name property. All payloads of type "a" will additionally have an a_data property, and all payloads of type b will additionally have a b_data property, itself made up of properties b_field1 and b_field2.

(Of course this very simplified to illustrate this question - the real use case has much longer and more complex json and many more types)

I would want to deserialize into C# classes, modeling a base class (containing at least the name property and possibly the type property), and two derived classes, one for those objects that are serialized in type "a" json, and one for those objects serialized in type "b" json.

I would imagine defining C# classes like:

    public class Base
    {
        public string type { get; set; }
        public string name { get; set; }
    }

    public class DeriviedA: Base
    {
        public string a_data { get; set; }
    }

    public class DervivedB : Base
    {
        public class DataB
        {
            public string b_field1 { get; set; }
            public string b_field2 { get; set; }
        }

        public DataB b_data { get; set; }
    }

Given that I don't know when a payload is incoming what type it is, I'll need to deserialize conditionally based on the the incoming type. But I don't "know" what type that is until I deserialize. I'm pretty sure the following would work, but it is not a particularly good solution, because it means I need to deserialize twice:

        public static Base Deserialize(string incomingJson)
        {
            Base tmp = JsonConvert.DeserializeObject<Base>(incomingJson);
            switch (tmp.type)
            {
                case "a":
                    return JsonConvert.DeserializeObject<DerivedA>(incomingJson);
                case "b":
                    return JsonConvert.DeserializeObject<DerivedB>(incomingJson);
                default:
                    throw new InvalidOperationException($"unable to deserialize payload of type {tmp.type}");
            }
        }

Now aside from needing to do the ungraceful double-deserialization, note that I would NOT be able to mark the Base class as abstract, even though I never want an instantiation of the Base class by itself.

Anyway, I am curious about ideas or strategies or best practices for doing this. My preference would be to use Newtonsoft for the deserialization, but it isn't a requirement.

Stephan G
  • 3,289
  • 4
  • 30
  • 49

1 Answers1

1

Just use a non-deserializing JSON reader to sniff the type before using a serializer.

Newtonsoft has a really easy way to do this:

dynamic message = JObject.Parse(json);
string type = message.type;

https://www.newtonsoft.com/json/help/html/QueryJsonDynamic.htm

David Browne - Microsoft
  • 80,331
  • 6
  • 39
  • 67