Home > Software engineering >  Cannot Deserialize Nested JSON in C#
Cannot Deserialize Nested JSON in C#

Time:02-16

I am new to programming and to C#. I'm using Visual Studio (latest) to write my app.

This is a console app that is attempting to read a log (text) file where each line is a separate JSON entry.

This is what a single item JSON entry looks like:

{
    "timestamp": "2022-02-09T07:05:59Z",
    "event": "Color",
    "Hex": "#FFFF00",
    "Name": "Yellow"
}

I establish the full path to the text file and store it in a string 'fileFullPath' and I'm 'using System.Text.Json'.

Each entry in the text file always has two fields - 'timestamp' and 'event'. I created a base class called 'LogHeader':

namespace LogModels
{
    public class LogHeader
    {
        public string TimeStamp { get; set; }
        public string Event { get; set; }

    }
}

Then, I created a class for each event and inherited from LogHeader:

public class Color : LogHeader
{
  public string Hex { get; set;}
  public string Name { get; set;}
}

Next, I read the file and start going through each line and writing to the console using a switch statement based on the 'event' field:

foreach (string line in File.ReadAllLines(fileFullPath))
{
  var logHeader = JsonSerializer.Deserialize<LogHeader>(line,options);

  switch (logHeader.Event)
  {
     case "Color":
       var eventColor = JsonSerializer.Deserialize<LogModels.Event.Color>(line, options);
       Console.WriteLine($"The color is {eventColor.Name}.");
       Console.WriteLine($"The Hex value is {eventColor.Hex}.");
     break;
  }

The console output is:

The color is Yellow.
The Hex value is #FFFF00.

The problem comes in with the nested JSON objects, which look like this:

{
    "timestamp": "2022-02-09T07:07:52Z",
    "event": "Carpet",
    "Shag": [
        {
            "Color": "Green",
            "Count": 3
        },
        {
            "Color": "Black",
            "Count": 104
        }
    ],
    "Pile": [
        {
            "Color": "Blue",
            "Count": 5
        },
        {
            "Color": "Beige",
            "Count": 13
        }
    ],
    "Outdoor": [
        {
            "Color": "Pebble",
            "Count": 300
        },
        {
            "Color": "Astroturf",
            "Count": 12
        }
    ]
}

At this point, I'm lost. I've tried creating a class called "Carpet" with child classes called "Shag", "Pile", etc. I've tried creating separate classes for each of the subtypes.

The desired outcome is for this to appear on the console:

Shag Carpet -
Green: 3
Black: 104
Pile Carpet -
Blue: 5
Beige: 13
Outdoor Carpet -
Pebble: 300
Astroturf: 12

I can't imagine this is as hard to do as I'm making it out to be, but I can't seem to find any examples to help me through it.

Also, I've only posted to this site a couple of times, and I'm not sure of the proper structure of replying to suggestions, etc.

Thank you for your help with this.

CodePudding user response:

Since you are new to programming and to C#, I highly recommend you to use Newtonsoft.Json serializer.

You can try this code

Data data = JsonConvert.DeserializeObject<Data>(json);

classes

public class Data
{
    [JsonProperty("timestamp")]
    public DateTime TimeStamp { get; set; }
    [JsonProperty("event")]
    public string Event { get; set; }
    public string Hex { get; set; }
    public string Name { get; set; }
    public List<ColourCount> Shag { get; set; }
    public List<ColourCount> Pile { get; set; }
    public List<ColourCount> Outdoor { get; set; }
}

public class ColourCount
{
    public string Color { get; set; }
    public int Count { get; set; }
}

you can test using reflection

    var props = data.GetType().GetProperties();

    foreach (var prop in props)
    {
        if (!prop.PropertyType.IsCollectible)
        {
            if(prop.GetValue(data)!=null)
            Console.WriteLine($" {prop.Name} : { prop.GetValue(data).ToString()} ");
        }
        else
        {
            Console.WriteLine($" { prop.Name} - ");

            var items = prop.GetValue(data) as IList<ColourCount>;

            foreach (var item in items)
            {
                Console.WriteLine($" {item.Color} : {item.Count}");
            }
        }
    }

result

 TimeStamp : 2022-02-09 7:07:52 AM 
 Event : Carpet 
 Shag - 
 Green : 3
 Black : 104
 Pile - 
 Blue : 5
 Beige : 13
 Outdoor - 
 Pebble : 300
 Astroturf : 12

if you still want to use Text.Json change property name attribute

Data data = System.Text.Json.JsonSerializer.Deserialize<Data>(json);

public class Data
{
    [JsonPropertyName("timestamp")]
    public DateTime TimeStamp { get; set; }
    [JsonPropertyName("event")]
    public string Event { get; set; }
    .....
}
  • Related