Create a StringConverter for System.Text.Json for JSON Serialization

In this article, we will see how to create StringConverter useful for deserializing non-string primitives like Int32, Bool, Double, etc. properties into String properties.

We shall be following the below high-level steps to create a converter using a basic pattern,

  • Create Custom Converter JsonConverter<T>
  • Override the Read method
  • Override the Write method
  • Register a Custom converter as a serializer option.
  • Perform serialize/deserialize

The above steps are already explained in detail in our last article.

As we know the new .NET /ASP.NET Core 3.1 and above framework has removed the dependency on JSON.NET and uses its own JSON serializer i.e ‘System.Text.Json‘.

Deserialization with the non-string value received for a string field shall result in a JsonException in .NET Core.

There are known limitations in the System.Text.Json serializer which are as per specification and design.

That means the best alternative is to write a custom converter.

Today in this article, we will cover below aspects,

System.Text.Json doesn’t deserialize non-string values like Int, Boolean and other primitives into string properties.

Any non-string value conversion produces the below exception like “System.Text.Json.JsonException: ‘The JSON value could not be converted to System.String”

StringConverter for System.Text.Json

To overcome the issue, one can write CustomConverter to allow literal true or false or Number conversion.

Below Read() method Reads and converts the JSON to type T.

JsonConverter<T> Converts an object or value to or from JSON.

Targeting Number(Int32 or Int etc).

         if (reader.TokenType == JsonTokenType.Number)
            {
                var stringValue = reader.GetInt32();
                return stringValue.ToString();
            }

Here is the complete code,

public class StringConverter : System.Text.Json.Serialization.JsonConverter<string>
    {
        public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {

            if (reader.TokenType == JsonTokenType.Number)
            {
                var stringValue = reader.GetInt32();
                return stringValue.ToString();
            }
            else if (reader.TokenType == JsonTokenType.String)
            {
                return reader.GetString();
            }

            throw new System.Text.Json.JsonException();
        }

        public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value);
        }

    }

Lets now deserialize the below JSON into the type Customer expecting string for integers

SystemTextJson Create a StringConverter for JSON Serialization

Target Type Customer as below,

SystemTextJson Create a StringConverter for JSON Serialization

Let’s register the Custom String Converted using JsonSerializerOptions.

StringConverter can be passed as the second argument to JsonSerializer.Deserialize method.

Using StringConverter

     
     var serializeOptions = new JsonSerializerOptions();
     serializeOptions.Converters.Add(new StringConverter());
     Customer empObject = JsonSerializer.Deserialize<Customer>(jsonOutPut, 
     serializeOptions);


Finally, conversion is successful,

SystemTextJson Create a StringConverter for JSON Serialization

References:

That’s All, Enjoy Coding !!

Do you have any comments or ideas or any better suggestions to share?

Please sound off your comments below.

Happy Coding !!



Please bookmark this page and share it with your friends. Please Subscribe to the blog to receive notifications on freshly published(2024) best practices and guidelines for software design and development.



4 thoughts on “System.Text.Json – Create a StringConverter for JSON Serialization

  1. God Bless you my Friend!

    I have been going through the process of preparing my code to migrate to System.Text.Json and later .Net Core, and this little fix helped solve the problem. And leaves the code looking cleaner and simpler for me, instead of Newtonsoft way. Makes it a lot more testable from what I can tell too.

  2. Hi,

    the above solution only gets the raw string value of Int32 and smaller types but the JSON Number type includes other types (float, decimal, etc.) as well. Also, Int32.ToString() may return a string which is different from the raw string value in the original JSON string due to local culture settings. Maybe Int32 is less susceptible to this than other number types (float, decimal, etc.) but it is a possibility. The following method simply parses the original JSON value into a string, so it returns the original raw value. You can later parse the string it returns in any way.

    private static string GetRawPropertyValue(Utf8JsonReader jsonReader)
    {
    ReadOnlySpan utf8Bytes = jsonReader.HasValueSequence ?
    jsonReader.ValueSequence.ToArray() :
    jsonReader.ValueSpan;
    return Encoding.UTF8.GetString(utf8Bytes);
    }

    I think Utf8JsonReader should have a public method that does this instead of everyone having to roll their own solution. I can’t see a good reason why the .NET team hid this. If you take a look at the source code of Utf8JsonReader at source.dot.net, you’ll see this is exactly what the class does in TryGetInt(), TryGetDouble() and similar methods.

    1. Hi Andras – Thanks for your inputs. That’s a good point and i see the method you have put in is useful and could serve for other raw types for numerics types. Thank you. Cheers!

Leave a Reply

Your email address will not be published. Required fields are marked *