0

I have a 3rdParty program that I receive JOSN data from. The Json can come in two ways and I have created two classes to represent the two JSON messages using http://json2csharp.com/

public class Data1
{
    public Content1 content { get; set; }

    public string name { get; set; }

    public string address { get; set; }

    public string age { get; set; }
}


public class Data2
{
    public Content2 content { get; set; }

    public string name { get; set; }

    public string address { get; set; }

    public string age { get; set; }
}

They are the same apart from Content1 and Content2 (I have classes for them also).

I want to deserialize the data like so:

var object1 = JsonConvert.DeserializeObject<Data1>(message1);
var object2 = JsonConvert.DeserializeObject<Data2>(message2);

But I do not know what message I will receive so how can I create one class that I can deserialize to and then use.

I have looked at this example https://www.jerriepelser.com/blog/deserialize-different-json-object-same-class/ and have attempted to create a SuperClass that has a:

[JsonConverter(typeof(SuperData))] 

but I'm not sure how to implement the ReadJson function.

Do I check the data that comes in and detect if content is type Content1 or Content2? If so how do I do this?

How do I then know what class has been deserialized so I can then know to check for the different content?

Here is the json: Data1

{
    "content": {
    "person_id": "1234",
    "timestamp": "2018-10-30 13:09:04.382885",
    "features": "old, cranky"
  },

  "name": "JoeBloggs",
  "address": "address1",    
  "age": 31,    
}

Data2

{
  "content": 
  {
    "detections": 1,

    "detection_boxes": [
      {
        "name": "JoeBloggs",
        "bbox": [
          1988.162842886987,
          -20.466329557695307,
          2662.417876180017,
          846.0808020362452
        ],
        "id": 3610
      }
    ],

    "timestamp": "2018-10-30 13:09:07.171000",
    ]
  },

  "name": "JoeBloggs",
  "address": "address1",    
  "age": 31,    
}

I have tried this:

[JsonConverter(typeof(MyDataConverter))]
public class MegaData
{
    public object content { get; set; }

    public string name { get; set; }

    public string address { get; set; }

    public string age { get; set; }
}

MyDataConverter has the following:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jObject = JObject.Load(reader);
        var content = jObject["message_content"];
        if (content["person_id"] != null)
        {
            return jObject.ToObject<Data1>();
        }
        else
        {
            return jObject.ToObject<Data2>();
        }
    }

Then I attempt to deserialize it as follows:

var alert = JsonConvert.DeserializeObject<MegaData>(message1); <-- EXCEPTION

**Unable to cast object of type 'Data1' to type 'MegaData'.**

What should my MegaData class look like for this to work??

Harry Boy
  • 4,159
  • 17
  • 71
  • 122
  • can you post the json string – Rahul Oct 30 '18 at 19:48
  • Have just added it, see how they are identical apart from 'content' – Harry Boy Oct 30 '18 at 19:57
  • So the difference is in the one case `content` has a `person_id` and in the other it has a `detections`? You'll need to examine the JSON object and then decide which way to deserialize it. Using [Linq to Json](https://www.newtonsoft.com/json/help/html/LINQtoJSON.htm) is a fairly easy way. First parse to a `JObject` and then check it for the property or properties that will allow you to tell the difference – Matt Burland Oct 30 '18 at 20:02

2 Answers2

1

Why can't you have a single class with both type and deserialize to that like

public class DetectionBox
{
    public string name { get; set; }
    public List<double> bbox { get; set; }
    public int id { get; set; }
}

public class Content
{
    public int detections { get; set; }
    public List<DetectionBox> detection_boxes { get; set; }
    public string timestamp { get; set; }
    public string person_id { get; set; }
    public string features { get; set; }
}

public class Data
{
    public Content content { get; set; }
    public string name { get; set; }
    public string address { get; set; }
    public int age { get; set; }
}


Data data = JsonConvert.DeserializeObject<Data>(json);
Rahul
  • 76,197
  • 13
  • 71
  • 125
1

So you can create a custom converter derived from JsonConverter and in the ReadJson you'd do something like this:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    var jObject = JObject.Load(reader);
    var content = jObject["content"];
    if (content["person_id"] != null) 
    {
        return jObject.ToObject<Data1>();
    }
    else
    {
        return jObject.ToObject<Data2>();
    }
}

If you aren't actually writing JSON, you can skip the WriteJson (have it throw a NotImplementedException) method and set CanWrite to return false (so it won't ever be called anyway).

Matt Burland
  • 44,552
  • 18
  • 99
  • 171
  • I have done this and it complains when I return from the ReadJson function that I am "Unable to cast object of type Data1 to my original class" .. how do I deal with this? – Harry Boy Oct 30 '18 at 20:30
  • @HarryBoy - what is your "original class"? You had a class called `Data1` and one called `Data2` – Matt Burland Oct 30 '18 at 20:37
  • "original class" as in the class that now has the custom json converter. Please see my edit. – Harry Boy Oct 30 '18 at 20:42