'Complicated Json to C# Object Deserialize with classes

I am trying to deserialize a json response I get from a web call. I have it 90 percent figured out. The only part I am having a hard time figuring out is there are these json arrays which have data in them and each array name is unique using the email address. I have not been able to figure out how to turn the Email Arrays into 1. Dynamic and having it create many lists or just a couple depending on what comes back in the response and also dynamically naming the list arrays to put the data into the Records class.

As you can see in the Records class I need this to be more dynamic and flexible to receive any and all emails.

Below is the json:

{
  "result": {
    "records": {
      "[email protected]": [
        {
          "OrderId": "d9535109-d305-4584-a503-8194bbcfcff2",
          "CompletedOrderId": "BCFCFF2",
          "CustomerId": 1212,
          "CompletedTime": "2020-10-26 13:32:02",
          "Email": "[email protected]",
          "ShippingFirstName": "Joe",
          "ShippingMiddleName": "",
          "ShippingLastName": "Blow",
          "LineItems": {
            "tfl.es.bluray": { "qty": 1 },
            "booklets.en.ebook": { "qty": 1 }
          }
        }
      ],
      "[email protected]": [
        {
          "OrderId": "7bf97b3a-bc46-411c-bc30-12563326dba0",
          "CompletedOrderId": "326DBA0",
          "CustomerId": 1212,
          "CompletedTime": "2020-10-26 20:07:44",
          "Email": "[email protected]",
          "ShippingFirstName": "Cleo",
          "ShippingMiddleName": "",
          "ShippingLastName": "Blue",
          "LineItems": {
            "tfl.es.bluray": { "qty": 1 },
            "booklets.en.ebook": { "qty": 1 },
            "aos.en.pb": { "qty": 1 },
            "course-tos.en.olr": { "qty": 1 },
            "pow-hsk-nofilm.en.combo": { "qty": 1 },
            "course-organizing.en.olr": { "qty": 1 }
          }
        }
      ],
      "[email protected]": [
        {
          "OrderId": "630f0dda-94c3-4b82-a070-2554004dce29",
          "CompletedOrderId": "04DCE29",
          "CustomerId": 12345,
          "CompletedTime": "2020-10-25 21:52:04",
          "Email": "[email protected]",
          "ShippingFirstName": "John",
          "ShippingMiddleName": "",
          "ShippingLastName": "Doe",
          "LineItems": {
            "tfl.es.bluray": { "qty": 1 },
            "booklets.en.ebook": { "qty": 1 },
            "aos.en.pb": { "qty": 1 },
            "course-tos.en.olr": { "qty": 1 },
            "pow-hsk-nofilm.en.combo": { "qty": 1 },
            "course-organizing.en.olr": { "qty": 1 },
            "oak-2007.en.cd": { "qty": 1 }
          }
        }
      ]
    },
    "errors": [
      {
        "id": "bademailaddress-yahoo.com",
        "message": "Email address 'bademailaddress-yahoo.com' is not a valid email address"
      }
    ]
  },
  "jsonrpc": "2.0",
  "id": 12345634523
} 

And the classes I made for the json deserialization:

public partial class JsonEmailDeSerializer
{
    [JsonProperty("result")]
    public Result Result { get; set; }

    [JsonProperty("jsonrpc")]
    public string Jsonrpc { get; set; }

    [JsonProperty("id")]
    public long Id { get; set; }
}

public partial class Result
{
    [JsonProperty("records")]
    public Records Records { get; set; }

    [JsonProperty("errors")]
    public List<Error> Errors { get; set; }
}

public partial class Error
{
    [JsonProperty("id")]
    public string Id { get; set; }

    [JsonProperty("message")]
    public string Message { get; set; }
}

public partial class Records
{
    [JsonProperty("[email protected]")]
    public List<MailCom> JoeblowGmailCom { get; set; }

    [JsonProperty("[email protected]")]
    public List<MailCom> CleobHotmailCom { get; set; }

    [JsonProperty("[email protected]")]
    public List<MailCom> JohndGmailCom { get; set; }
}

public partial class MailCom
{
    [JsonProperty("OrderId")]
    public Guid OrderId { get; set; }

    [JsonProperty("CompletedOrderId")]
    public string CompletedOrderId { get; set; }

    [JsonProperty("CustomerId")]
    public long CustomerId { get; set; }

    [JsonProperty("CompletedTime")]
    public DateTimeOffset CompletedTime { get; set; }

    [JsonProperty("Email")]
    public string Email { get; set; }

    [JsonProperty("ShippingFirstName")]
    public string ShippingFirstName { get; set; }

    [JsonProperty("ShippingMiddleName")]
    public string ShippingMiddleName { get; set; }

    [JsonProperty("ShippingLastName")]
    public string ShippingLastName { get; set; }

    [JsonProperty("LineItems")]
    public Dictionary<string, LineItem> LineItems { get; set; }
}

public partial class LineItem
{
    [JsonProperty("qty")]
    public long Qty { get; set; }
}

public partial class JsonEmailDeSerializer
{
    public static JsonEmailDeSerializer FromJson(string json) => JsonConvert.DeserializeObject<JsonEmailDeSerializer>(json, FedExShipper.Converter.Settings);
}

public static class Serialize
{
    public static string ToJson(this JsonEmailDeSerializer self) => JsonConvert.SerializeObject(self, FedExShipper.Converter.Settings);
}

internal static class Converter
{
    public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
    {
        MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
        DateParseHandling = DateParseHandling.None,
        Converters =
        {
            new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
        },
    };
}


Solution 1:[1]

Common approach to deserializing json with dynamic property names is to use Dictionary<string, ...>, in this case - Dictionary<string, List<MailCom>> can be used for Records property:

public partial class Result
{
    [JsonProperty("records")]
    public Dictionary<string, List<MailCom>> Records { get; set; }

    [JsonProperty("errors")]
    public List<Error> Errors { get; set; }
}

Json.NET can treat json object properties as keys for dictionary which makes it suitable to deserialize such dynamic data. The same is true for System.Text.Json.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1