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.

  1. The names of the properties are with spaces, for example Time Series (Daily) or 1. open
  2. 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:

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 :)

comments powered by Disqus