DEV Community

Galina Melnik
Galina Melnik

Posted on • Edited on

JsonConverter<T>

I want to create home pet project with Mars wheather. Thanks God NASA have a public API with data.
Test URL https://api.nasa.gov/insight_weather/?api_key=DEMO_KEY&feedtype=json&ver=1.0
And there is their json for today :
{
"782": {
"First_UTC": "2021-02-06T17:08:11Z",
"Last_UTC": "2021-02-07T17:47:46Z",
"Month_ordinal": 12,
"Northern_season": "late winter",
"PRE": {
"av": 721.77,
"ct": 113450,
"mn": 698.8193,
"mx": 742.2686
},
"Season": "winter",
"Southern_season": "late summer",
"WD": {
"most_common": null
}
},
"783": {
"First_UTC": "2021-02-07T17:47:46Z",
"Last_UTC": "2021-02-08T18:27:22Z",
"Month_ordinal": 12,
"Northern_season": "late winter",
"PRE": {
"av": 722.186,
"ct": 107270,
"mn": 698.7664,
"mx": 743.1983
},
"Season": "winter",
"Southern_season": "late summer",
"WD": {
"most_common": null
}
}, ... irrelevant
"sol_keys": [... irrelevant],
"validity_checks": { ...irrelevant }
}

I've created a project using netcoreapp3.0 and wanted to use System.Text.Json library. My first wrong way to do it was :

var dict = await JsonSerializer.DeserializeAsync<Dictionary<string, MarsWheather>>(stream);
Enter fullscreen mode Exit fullscreen mode

But I caught an exception

System.Text.Json.JsonException: The JSON value could not be converted to MarsWheather. Path: $.sol_keys | LineNumber: 120 | BytePositionInLine: 15.

BOOM!
That's why I've created custom JsonConverter. I hope this code will helpful for community.
UPDATE 03/03/2021 : There was a bug with my code. This is a new version without it.
Data classes is :

[JsonConverter(typeof(MarsWheatherRootObjectConverter))]
    public class MarsWheatherRootObject
    {
        public List<MarsWheather> MarsWheather { get; set}
    }
    public class MarsWheather {
        public int Sol { get; set; }
        [JsonPropertyName("First_UTC")]
        public DateTime FirstUTC { get; set; }
        [JsonPropertyName("Last_UTC")]
        public DateTime LastUTC { get; set; }
        [JsonPropertyName("Season")]
        [JsonConverter(typeof(JsonStringEnumConverter))]
        public Season MarsSeason { get; set; }
        [JsonPropertyName("PRE")]
        public DataDescription AtmosphericPressure { get; set; }
    }
Enter fullscreen mode Exit fullscreen mode

I've created an class wrapper (MarsWheatherRootObject) to use class attribute.

internal class MarsWheatherRootObjectConverter : JsonConverter<MarsWheatherRootObject>
    {
        public override MarsWheatherRootObject Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            var root = new MarsWheatherRootObject();
            var list = new List<MarsWheather>();
            while (reader.Read())
            {
                switch (reader.TokenType)
                {
                    case JsonTokenType.PropertyName:
                    case JsonTokenType.String:
                        var keyStr = reader.GetString();
                        int key;
                        if (!int.TryParse(keyStr, out key))
                        {
                            reader.Skip();
                        }
                        else
                        {
                            var value = JsonSerializer.Deserialize<MarsWheather>(ref reader, options);
                            value.Sol = key;
                            list.Add(value);
                        }
                        break;
                    default: break;
                }
            }
            root.MarsWheather = list;
            return root;
        }

        public override void Write(Utf8JsonWriter writer, MarsWheatherRootObject value, JsonSerializerOptions options)
        {
            throw new NotImplementedException();
        }
    }
Enter fullscreen mode Exit fullscreen mode

I don't need to serialize the object. That's why I don't write code for Write method by now.

Top comments (0)