System.Text.Json: Convert JSON with a decimal value "NA"

3.7k views Asked by At

I use .NET6 and Blazor. I read same data from an API. To convert the JSON I use System.Text.Json. In the JSON I expect a list of float/decimal but in same cases instead of a list of numbers there is the string "NA".

In this case, the conversion fails and there is an exception on this line

return JsonSerializer.Deserialize<APIResponse>(responseContent);

I saw that with JSON.NET it is possible to write some custom code to avoid this error. An example is

Root obj = JsonConvert.DeserializeObject<Root>(
json, new JsonSerializerSettings
{
    Error = (sender, args) =>
    {
        Reading reading = args.CurrentObject as Reading;

        if (reading != null && args.ErrorContext.Member.ToString() == "temperature")
        {
            reading.Temperature = null;
            args.ErrorContext.Handled = true;
        }
    }
});

but there is nothing similar on System.Text.Json.

How can I fix it?

2

There are 2 answers

0
shocks On

Error handling is not implemented in System.Text.Json

You can follow the issue here: https://github.com/dotnet/runtime/issues/38049

0
Guru Stron On

You can create custom json converter. For example:

public class CustomDecimalConverter : JsonConverter<decimal>
{
    public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        switch (reader.TokenType)
        {
            case JsonTokenType.String:
                if (reader.GetString().Equals("NA", StringComparison.InvariantCultureIgnoreCase)) // possibly check reader.GetString() for null
                {
                    return default;
                }

                throw new JsonException("bla"); // some exception
            case JsonTokenType.Number:
                return reader.GetDecimal();
            default:
                throw new ArgumentOutOfRangeException();
        }
    }

    public override void Write(Utf8JsonWriter writer, decimal value, JsonSerializerOptions options) =>
        writer.WriteNumberValue(value);
}

And mark needed properties with it (possibly need to create similar ones for double/float). Example usage:

class MyClass
{
    [JsonConverter(typeof(CustomDecimalConverter))]
    public decimal id1 { get; set; }
    [JsonConverter(typeof(CustomDecimalConverter))]
    public decimal id2 { get; set; }
}

var json = "{\"id1\": 1, \"id2\": \"NA\"}";
var myClass = JsonSerializer.Deserialize<MyClass>(json);
Console.WriteLine($"{myClass.id1} {myClass.id2}"); // prints "1 0"