How to represent and serialize a data structure which requires duplicate keys?

Viewed 96

I'm working with a third-party API where you send an order along with an array of options you want to add to the order. Each Option has an OptionId.

You'd assume the required JSON would look something like this:

{  
   //More properties cut for brevity
   "options":[  
      {  
         "optionId":"ID 1"
      },
      {  
         "optionId":"ID 2"
      }
   ]
}

Instead, the required JSON actually looks like this:

{  
   //More properties cut for brevity
   "options":[  
      {  
         "optionId":"ID 1",
         "optionId":"ID 2"
      }
   ]
}

Is there any way I can represent that data structure in C#? And if yes, is there any way I can tell Json.NET to serialize it the way the API requires?

1 Answers

The desired JSON is technically valid, though not recommended because having duplicate keys in an object makes it much more difficult to work with. I understand this is a third party API, and you don't have any other choice, but I want to make clear to future readers that this is a bad design.

To represent the option IDs in C#, you can use a simple List<string>. You will need to make a custom JsonConverter to write out the desired structure to the JSON. We'll call it OptionListConverter. So declare the option list as shown below:

class Order
{
    [JsonProperty("options")]
    [JsonConverter(typeof(OptionListConverter))]
    public List<string> OptionIds { get; set; }
}

Then define the OptionListConverter like this:

class OptionListConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(List<string>);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var list = (List<string>)value;
        writer.WriteStartArray();
        writer.WriteStartObject();
        foreach (var id in list)
        {
            writer.WritePropertyName("optionId");
            writer.WriteValue(id);
        }
        writer.WriteEndObject();
        writer.WriteEndArray();
    }

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

You can then create the desired JSON like this:

var order = new Order
{
    OptionIds = new List<string> { "ID 1", "ID 2" }
};

var json = JsonConvert.SerializeObject(order, Formatting.Indented);

Working demo: https://dotnetfiddle.net/rEYl8p

Related