10

I have an odd Json result set that has a repeating (but changeable) property that I need to convert to an array of an object type, e.g.

"result": {
    "documents": {
        "abcd": {
            "propertyX": 0
            "propertyY": "A"
        },
        "efgh": {
            "propertyX": 5
            "propertyY": "B"
        },
        "ijkl": {
            "propertyX": 2
            "propertyY": "C"
        }
    }
}

What I'd like to do is to have my Result object with a document property, and this have an array of "items". Each item object will contain "propertyX", "propertyY" etc. Unfortunately "abcd", "efgh" etc. are a random list of items but they are rendered as distinct properties.

Is there a straightforward way of handling this or would I need a custom converter?

1

1 Answer 1

14

Yes, the straightforward way to handle this is to use a Dictionary<string, Item> for your documents property. The random document names would become the keys of the dictionary. You can declare the classes like this:

class RootObject
{
    public Result Result { get; set; }
}

class Result
{
    public Dictionary<string, Item> Documents { get; set; }
}

class Item
{
    public string PropertyX { get; set; }
    public string PropertyY { get; set; }
}

Then deserialize the JSON like this:

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

Fiddle: https://dotnetfiddle.net/lTDGj3


If you do not want a dictionary in your class and instead would really rather have an array (or list) of items, then yes, you would need a converter. In that case, you would declare your classes like this:

class RootObject
{
    public Result Result { get; set; }
}

class Result
{
    [JsonConverter(typeof(DocumentListConverter))]
    public List<Item> Documents { get; set; }
}

class Item
{
    public string Name { get; set; }
    public string PropertyX { get; set; }
    public string PropertyY { get; set; }
}

The custom converter class for the document list would look something like this:

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        List<Item> items = new List<Item>();
        foreach (JProperty prop in jo.Properties())
        {
            Item item = prop.Value.ToObject<Item>();
            item.Name = prop.Name;
            items.Add(item);
        }
        return items;
    }

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

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

And you would deserialize in the same way as before:

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

Fiddle: https://dotnetfiddle.net/xWRMGP

Sign up to request clarification or add additional context in comments.

1 Comment

Simple is great; thank you very much for both options

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.