Use the JsonConverter attribute to parse complex JSON object into a C# class
I was working lately with some complex JSON objects coming from the alphavantage, an API for getting meta information about stocks, currencies and the world economy in general, and had to overcome major issues before being able to deserialize the strings into my C# POCO classes.
Consider this JSON string. We focus on the following part of the JSON result, which pose two difficulties, when we try to convert it into a C# structure in our application.
- The names of the properties are with spaces, for example Time Series (Daily) or 1. open
- The names of other properties are variant, for example 2023-04-06, which we cannot directly map to a C# property, since the name of it changes based on a date.
"Time Series (Daily)": {
"2023-04-06": {
"1. open": "132.16",
"2. high": "132.6",
"3. low": "130.315",
"4. close": "130.5",
"5. adjusted close": "130.5",
"6. volume": "3050581",
"7. dividend amount": "0.0000",
"8. split coefficient": "1.0"
}
}
We will define the following property in our POCO C# class:
[JsonProperty("Time Series (Daily)")]
[JsonConverter(typeof(TimeSeriesConverter))]
public TimeSeries TimeSeries { get; set; }
With the JsonProperty
we are solving the first problem. We are mapping a property with invalid characters, in this case spaces to a C# property named TimeSeries
.
For solving the second issue we will have to create a custom JsonConverter
and override the methods of this abstract class. Pay attention to the following code parts of the ReadJson
method:
- The JsonReader object contains the json that we want to parse
- The objectType contains the type of the object we applied the converter to
- The existingValue is null because we do not have any value in our property already
- The serializer can be used to deserialize the object
- We load the complete JSON object into a
JObject
by using theLoad(reader)
method - We parse the value of each item of the JObject and we convert its
Value
into our POCO object by using theToObject<T>
method.
public class TimeSeriesConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
return string.Empty;
}
JObject obj = JObject.Load(reader);
List<Daily> dailies = new List<Daily>();
foreach (var item in obj)
{
string name = item.Key;
JToken token = item.Value;
Daily daily = token.ToObject<Daily>();
daily.Date = DateTime.ParseExact(name, "yyyy-MM-dd", CultureInfo.InvariantCulture);
dailies.Add(daily);
}
return new TimeSeries { Dailies = dailies };
}
public override bool CanWrite
{
get { return false; }
}
public override bool CanConvert(Type objectType)
{
return false;
}
}
Did you find this article helpful? Drop me a line with your thoughts :)