In C#, how do I model a JSON object with multiple nested arrays?
Asked Answered
I

3

8

I am getting this JSON response from a system I am connecting to and trying to figure out the best way to deserialize it into a C# object. I am currently using RestSharp which seems pretty straight forward to use but the format of the JSON is baffling me a bit. Here is the format that its coming in as:

[
  {"name": "Tickets:",
   "schema": [
    {"dataType": "string", "colName": "First", "idx": 0}, 
    {"dataType": "string", "colName": "Second", "idx": 1}, 
    {"dataType": "string", "colName": "Name", "idx": 2}
   ], 
   "data": [
            ["bill", "test", "joe"],
            ["bill2", "test2", "joe2"],
            ["bill3", "test3", "joe3"]
           ]
  }
] 

Here is my current code:

var url = "http://myUrl:10111";
var client = new RestClient { BaseUrl = url };

var request = new RestRequest { Method = Method.GET, Resource = "/search?fmt=Json", RequestFormat = DataFormat.Json };
request.AddHeader("accept", "application/json");

var response = client.Execute(request);
var wptResponse = new JsonDeserializer().Deserialize<TicketResults>(response);
return wptResponse;

but as stated above I am trying to figure out the correct way to model the TicketResults object to support deserializing this message above.

Ideally I would like something like this:

 public class TicketResults
 {
     public List<Ticket> Tickets {get;set;}
 }

 public class Ticket
 {
     public string First {get;set;}
     public string Second {get;set;}
     public string Name {get;set;}
 }

and in this example above would get three entries in the Tickets collection.

Also, is the above JSON format normal as i have never seen this broken out into separate schema and data section (I can see where it might save some space but in this case the messages are not that big)

Imponderabilia answered 11/8, 2014 at 22:11 Comment(5)
Have a look at the newtonsoft library for deserialize json into an object. You can also use data annotations above the properties in the class to map them to the json properties.Strother
the question is more about this funky schema (versus any particular issue with RestSharp).Imponderabilia
Yeah ive used newtonsoft before to handle a funky scheme and it is by far the best. Just pointing th OP to a possible easier solutionStrother
Since the number and names of the properties in a generated class are not known at compile time, how do you plan to utilise them? i.e, suppose when you run your code the REST service gives you the schema for a class named "XYZ" with properties "Foo" and "Bar". But in order to instantiate and use this class, you'd have to know beforehand the name of the generated class, and the names of its properties.Encourage
@Asad - agree . . i am just going to ignore the schema for now and assume hard coded fields (as i was told the schema won't change without letting me know and updateImponderabilia
O
4

I agree the json format is quite ... goofy. Here's how to model your dto:

    public class JsonDto
    {
        public string name { get; set; }
        public Schema[] schema {get; set;}
        public string[][] data { get; set; }
    }
    public class Schema
    {
        public string dataType { get; set; }
        public string colName { get; set; }
        public int idx { get; set; }
    }

I was able to get your string (unaltered) to deserialize with JSON.Net like this:

var jsonDto = JsonConvert.DeserializeObject<JsonDto[]>(json);

Let me know if you're still having trouble.

Outrun answered 12/8, 2014 at 3:5 Comment(4)
when i use this data structure above i get the following error: Unable to cast object of type 'RestSharp.JsonArray' to type 'System.Collections.Generic.IDictionary`2[System.String,System.Object]'.Imponderabilia
i had to return List<JsonDto> (even though there is only always 1 items in the list.Imponderabilia
I tested this solution. Its working as suggested in this answer.Swirsky
@Imponderabilia yea note the DeserializeObject<JsonDto[]> - specifically JsonDto[]. This is part of the goofiness (is that a word?) of the json- the root element is an array even though there's only one object in the array.Outrun
E
24

In Visual Studio 2012 and up and you can go to Edit > Paste Special > Paste JSON as classes. It produces the following code given your example pasted from clipboard.

public class Rootobject
{
    public Class1[] Property1 { get; set; }
}

public class Class1
{
    public string name { get; set; }
    public Schema[] schema { get; set; }
    public string[][] data { get; set; }
}

public class Schema
{
    public string dataType { get; set; }
    public string colName { get; set; }
    public int idx { get; set; }
}

string json = File.ReadAllText("json.txt");
Rootobject root = new Rootobject();
root.Property1 = JsonConvert.DeserializeObject<Class1[]>(json);
Extend answered 12/8, 2014 at 3:9 Comment(5)
This is not the class the OP is looking to deserialize to. Please see the question.Encourage
@Asad Just tested this and it worked fine. Added the test to my answer. Not only does this solve his problem with his current JSON structure, but it solves all future problems of trying to map a JSON structure to a class. This is what I call giving someone a fishing pole instead of a fish. Paste as JSON is a great feature which can save a lot of time and effort manually creating model classes.Extend
The naming is off on the object (bc of the auto-generated class from pasting), but it's the same (I just worked around the need for RootObject in my answer). Also, +1 for paste JSON- did not know that!Outrun
Awesome hadn't seen this saved me loads of time thanks!Yam
Thanks so much. This is still the way in vs2017.Punctuality
O
4

I agree the json format is quite ... goofy. Here's how to model your dto:

    public class JsonDto
    {
        public string name { get; set; }
        public Schema[] schema {get; set;}
        public string[][] data { get; set; }
    }
    public class Schema
    {
        public string dataType { get; set; }
        public string colName { get; set; }
        public int idx { get; set; }
    }

I was able to get your string (unaltered) to deserialize with JSON.Net like this:

var jsonDto = JsonConvert.DeserializeObject<JsonDto[]>(json);

Let me know if you're still having trouble.

Outrun answered 12/8, 2014 at 3:5 Comment(4)
when i use this data structure above i get the following error: Unable to cast object of type 'RestSharp.JsonArray' to type 'System.Collections.Generic.IDictionary`2[System.String,System.Object]'.Imponderabilia
i had to return List<JsonDto> (even though there is only always 1 items in the list.Imponderabilia
I tested this solution. Its working as suggested in this answer.Swirsky
@Imponderabilia yea note the DeserializeObject<JsonDto[]> - specifically JsonDto[]. This is part of the goofiness (is that a word?) of the json- the root element is an array even though there's only one object in the array.Outrun
H
1

Do you have any control over the structure of the JSON being returned? It's kind of wacky. For some reason the field names and the data is separated out. If the format was a little more sensible like:

[
    {
        "First": "bill",
        "Second": "test",
        "Name": "joe"
    },

    {
        "First": "bill2",
        "Second": "test2",
        "Name": "joe2"
    },
]

Then you would have a shot at serializing it to your Ticket class. However, without reworking the JSON structure, which I don't recommend you do, the C# class that you are serializing to will have to match the JSON structure.

I suppose you could come up with an intermediary class to hold the JSON data as it comes to you. Then you could loop over those objets and create instances of the Ticket class out of them. At least that way you end up with a data structure you can work with.

Homologous answered 11/8, 2014 at 22:57 Comment(1)
I unfortunately do not have control over the formatImponderabilia

© 2022 - 2024 — McMap. All rights reserved.