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?
Json.NET has excellent support for serializing and deserializing collections of objects. To serialize a collection - a generic list, array, dictionary, or your own custom collection - simply call the serializer with the object you want to get JSON for.
That being said, it's known that parsing to JObject can be slower than deserializing -- see stackify.com/top-11-json-performance-usage-tips which states, Parsing generic JSON to a JSON.net JObject ... is slower (~20%) than reading that data in to a defined class type.
JsonPropertyAttribute indicates that a property should be serialized when member serialization is set to opt-in. It includes non-public properties in serialization and deserialization. It can be used to customize type name, reference, null, and default value handling for the property value.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With