0

I am working on a C# project where I need to call an API and parse through the JSON response.

The JSON response:

{
    "version": "3.9.1",
     "data": {
        "obj1": {
            "version": "1.0.0",
            "id": "obj1",
            "name": "Object 1",
            "title": "Object 1",
            "info": {
                "info1": 8,
                "info2": 4,
                "info3": 3
            },
            "image": {
                "full": "Object1.png",
                "w": 64,
                "h": 64
            },
            "tags": [
                "Tag1",
                "Tag2"
            ]
        },
        "obj2": {
            "version": "1.0.0",
            "id": "obj2",
            "name": "Object 2",
            "title": "Object 2",
            "info": {
                "info1": 1,
                "info2": 6,
                "info3": 7
            },
            "image": {
                "full": "Object2.png",
                "w": 64,
                "h": 64
            },
            "tags": [
                "Tag1",
                "Tag6"
            ]
        },
        "obj3": {
            "version": "1.0.0",
            "id": "obj3",
            "name": "Object 3",
            "title": "Object 3",
            "info": {
                "info1": 0,
                "info2": 1,
                "info3": 2
            },
            "image": {
                "full": "Object3.png",
                "w": 64,
                "h": 64
            },
            "tags": [
                "Tag7",
                "Tag8"
            ]
        }
    }
}

With this response, I want to loop through all the objects located inside data. The number of objects inside data isn't always the same; it is possible that there will only be one object or ten objects.

The problem I ran into is that I can't loop through the data property because of the following error:

foreach statement cannot operate on variables of type 'Objects' because 'Objects' does not contain a public instance or extension definition for 'GetEnumerator'

I know why I am getting the error, but I can't find a way of fixing my problem.

My code:

MainWindow.xaml.cs

WebRequest request = WebRequest.Create(path);
WebResponse response = request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());

string ReaderJson = reader.ReadToEnd();

var JsonResponse = JsonConvert.DeserializeObject<Response>(ReaderJson);

foreach (var obj in JsonResponse.data)
{
    Console.WriteLine(obj.ToString());
}

JsonParser.cs

    public class Response
    {
        public string version { get; set; }
        public Objects data { get; set; }
    }

    public class Objects
    {
        public string id { get; set; }
        public string name { get; set; }
        public string title { get; set; }
        public Info info { get; set; }
        public Images images { get; set; }
    }

    public class Info
    {
        public int info1 { get; set; }
        public int info2 { get; set; }
        public int info3 { get; set; }
    }

    public class Images
    {
        public string full { get; set; }
        public int w { get; set; }
        public int h { get; set; }
    }

How can I loop through all the objects inside data without calling them using obj1, obj2, etc.?

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
  • 2
    Your data model doesn't map to your JSON data. Your `data` property should be a `Dictionary`. (As an aside, the class name `Objects` is a bit peculiar here; only collections should be named as plurals.) – Jeremy Caney May 03 '21 at 20:40
  • ahh alright thanks! and yes I wanted to rename the Objects class afterwards but I first wanted to fix this problem. Just a bad practice that I sadly enough do quite often. – MrMilkshake May 03 '21 at 21:01
  • 1
    FYI: I formalized that comment as an answer with a bit more detail—though it sounds like you already got the main points from my comment. Let me know if that works for you! – Jeremy Caney May 03 '21 at 21:03
  • I'm guessing that data is not what you're thinking it is. It looks like data is an object, not a collection. – Grant May 03 '21 at 20:30

1 Answers1

1

The problem here is that your JSON schema defines a dictionary for data, but your data property returns a single instance of your Objects class.

Data Model

What you want is for your Response class to look something like this:

public class Response
{
    public string version { get; set; }
    public Dictionary<string, Objects> data { get; set; }
}

Everything else should be fine.

Looping Through Data

Given the above, you can now loop through the data dictionary using something like:

foreach (var obj in JsonResponse.data)
{
    Console.WriteLine(obj.Key);
}

Note: When looping through a Dictionary<TKey, TValue>, an enumeration of KeyValuePair<TKey, TValue>s will be returned, with your key (i.e., obj1) in the Key property, and your object in the Value property.

Naming Conventions

Obviously, the name Objects doesn't makes sense here, since it represents a single object, not a collection of objects. I'm keeping it Objects for consistency with your code, but you'll want to give it a singular name. I assume that was just left over from you wanting it to represent a collection.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
  • 1
    @MrMilkshake: Glad to hear! As an aside, if you control the data, an alternative approach would be to treat `data` as an array in your JSON, and then map it to a `Collection<>`—or, if you still want it to be keyed, then a `KeyedCollection<>` based on your `id` property. – Jeremy Caney May 03 '21 at 21:31
  • Yeah it would be alot easier if data was indeed a array but sadly enough the JSON comes as a response from an API and I am not able to change it :( but the `KeyedCollection<>` is a great alternative i'll give it a try :D – MrMilkshake May 03 '21 at 21:39