-3

From an external API I am receiving the below JSON response for the bank details of a customer.

{
   "bankDetails":[
      {
         "ABC Bank":[
            {
               "sNo":1,
               "acNo":"1235465",
               "acBalance":"100.25"
            },
            {
               "sNo":2,
               "acNo":"1235467",
               "acBalance":"50.25"
            }
         ],
         "bankName":"ABC Bank",
         "totalAmount":"150.50"
      },
      {
         "XYZ Bank":[
            {
               "sNo":1,
               "acNo":"1248565",
               "acBalance":"75.25"
            }
         ],
         "bankName":"XYZ Bank",
         "totalAmount":"75.25"
      },
      {
         "BCD Bank":[
            {
               "sNo":1,
               "acNo":"145665",
               "acBalance":"10.25"
            },
            {
               "sNo":2,
               "acNo":"195267",
               "acBalance":"5.25"
            }
         ],
         "bankName":"BCD Bank",
         "totalAmount":"15.50"
      }
   ]
}

I need to deserialize this to a C# class using JSON.Net. What should be structure of the C# class as the first key is dynamic?. The first key with bank name returned will be different for each customer

Anoop
  • 13
  • 2

1 Answers1

0

The typical solution to dealing with dynamic keys is to use a Dictionary<string, T> in place of a regular class. See How can I deserialize a child object with dynamic (numeric) key names? for an example of this. However, that solution doesn't really work for your case, because there are other properties in the same object which do not have dynamic keys (the bankName and totalAmount), and the values of those properties are primitives whereas the value of dynamic property is an array of bank accounts. A better solution here is to use a JsonConverter.

Before we get to that, we need to set up a class structure to deserialize into. This is pretty straightforward:

class RootObject
{
    public List<Bank> BankDetails { get; set; }
}

[JsonConverter(typeof(BankConverter))]
class Bank
{
    public string BankName { get; set; }
    public decimal TotalAmount { get; set; }
    public List<Account> Accounts { get; set; }
}

class Account
{
    [JsonProperty("sNo")]
    public int SequenceNumber { get; set; }
    [JsonProperty("acNo")]
    public string AccountNumber { get; set; }
    [JsonProperty("acBalance")]
    public decimal Balance { get; set; }
}

You'll notice that I've added a few [JsonProperty] attributes in the Account class to map the shorthand property names in the JSON to friendlier property names in that class. And the [JsonConverter] attribute on the Bank class tells the serializer that we will be using a custom BankConverter to handle that class.

Here is the code for the BankConverter. It uses a JObject internally to make it easier to read and work with the JSON.

class BankConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Bank);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject obj = JObject.Load(reader);
        Bank bank = new Bank();
        // populate the known properties (bankName and totalAmount)
        serializer.Populate(obj.CreateReader(), bank);
        // now handle the dynamic key
        bank.Accounts = obj[bank.BankName].ToObject<List<Account>>(serializer);
        return bank;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

With these classes in place, you can deserialize the JSON like this:

var root = JsonConvert.DeserializeObject<RootObject>(json);

Here is a working demo: https://dotnetfiddle.net/knsRLv

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300