System.Text.Json.Serialization - Read Numbers from JSON strings

Lets say you are POSTing a json that looks like this:

{
  "someNumber": "123"
}

…to a server-side web api DTO that looks like this:

public class Stuff
{
    public int? SomeNumber { get; set; }
}

This thing will fail since the number in the json is quoted. It looks like System.Text.Json is adding JsonNumberHandling.AllowReadingFromString which will accomplish this once .NET 5.0 is finally released.

In the meantime, I wrote a custom converter which works with nullable ints.

StringJsonConverter.cs

public class StringJsonConverter : JsonConverter<int?>
{
    public override int? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return reader.TokenType switch
        {
            JsonTokenType.Number => reader.GetInt32(),
            JsonTokenType.Null => null,
            JsonTokenType.String => int.TryParse(reader.GetString(), out var parsed) ? parsed : (int?)null,
            _ => throw new ArgumentOutOfRangeException(nameof(reader), reader.TokenType, "Cannot parse unexpected JSON token type.")
        };
    }

    public override void Write(Utf8JsonWriter writer, int? value, JsonSerializerOptions options)
    {
        if (value.HasValue)
        {
            writer.WriteNumberValue(value.Value);
        }
        else
        {
            writer.WriteNullValue();
        }
    }
}

Don’t forget to register it in one of the many ways you can do so:

  • Add an instance of the converter class to the JsonSerializerOptions.Converters collection.
  • Apply the [JsonConverter] attribute to the properties that require the custom converter.
  • Apply the [JsonConverter] attribute to a class or a struct that represents a custom value type.

I chose the first option and threw it in my startup:

services.AddControllers()
        .AddJsonOptions(
            options =>
            {
                // TODO: replace StringToIntJsonConverter with JsonNumberHandling.AllowReadingFromString once we move to .NET 5
                options.JsonSerializerOptions.Converters.Add(new StringToIntJsonConverter());
            });
comments powered by Disqus