DEV Community

Cover image for Reading JSON with custom formats in C#
Diego Faria
Diego Faria

Posted on

Reading JSON with custom formats in C#

The Problem

The JSON is the most common type used by APIs to respond requests.
Sometimes we receive contents that aren't possible to parse using built-in types in C#. Example, imagine that an API responds a date like Brazilian format (dd/MM/yyy) and we need to read this value in our app.

For this example, lets assume the JSON below:

{"name":"John","birthDate":"31/12/1990"}
Enter fullscreen mode Exit fullscreen mode

Preparing the scenario

First of all, we need to create the class that represents the person.

public class Person
{
    [JsonPropertyName("name")]
    public string Name { get; set; }

    [JsonPropertyName("birthDate")]
    public DateTime BirthDate { get; set; }

    public override string ToString()
    {
        return $"Name: {Name} | BirthDate: {BirthDate}";
    }
}
Enter fullscreen mode Exit fullscreen mode

Now we need to create a variable that represents the JSON.

public class Program
{
    public static string jsonExample = "{"
        + "\"name\":\"John\","
        + "\"birthDate\":\"31/12/1990\""
        + "}";

    public static void Main(string[] args)
    {
    }
}
Enter fullscreen mode Exit fullscreen mode

And finally we create the parser using the built-in JsonSerializer.Deserialize

public class Program
{
    public static string jsonExample = "{"
        + "\"name\":\"John\","
        + "\"birthDate\":\"31/12/1990\""
        + "}";
    public static void Main(string[] args)
    {

        var person = JsonSerializer.Deserialize<Person>(jsonExample);
        Console.WriteLine(person);
    }
}
Enter fullscreen mode Exit fullscreen mode

Running the code

When we try to run the code we receive an exception informing System.FormatException : The JSON value is not in a supported DateTime format. because the C# don't know how to apply the custom date to the type DateTime.

The solution

To solve this problem, we need to create a custom json converter using the built-in abstract class JsonConverter<T>.

First we need to create a class that inherit from JsonConverter<T> where T is the type of expected result. In this case DateTime.

public class MyCustomJsonConverter : JsonConverter<DateTime>
{

}
Enter fullscreen mode Exit fullscreen mode

After that we implements the inherited methods.

public class MyCustomJsonConverter : JsonConverter<DateTime>
{
    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }

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

Now we need to implement two methods, the first one is to read a custom json value and the second one is to write a custom json value. For this purpose we will use only the first one, because we are reading a value.

The system will pass the expected json using the Utf8JsonReader reader parameter.
As Utf8JsonReader is a struct, it's necessary to get the value using the GetString() that returns a string? type.

And finally we use the DateTime.ParseExact() to format the date as expected.

public class MyCustomJsonConverter : JsonConverter<DateTime>
{
    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var dateTimeFromJson = reader.GetString()!;

        return DateTime.ParseExact(dateTimeFromJson, "dd/MM/yyyy", CultureInfo.InvariantCulture);
    }

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

Ok, we have a custom converter, now we need to apply this converter on property Person.BirthDate to the serializer do the hard work for us.

It's simple. We just need to decorate the BirthDate property with the attribute JsonConverter() that expects a type of converter.

public class Person
{
    [JsonPropertyName("name")]
    public string Name { get; set; }

    [JsonPropertyName("birthDate")]
    [JsonConverter(typeof(MyCustomJsonConverter))]
    public DateTime BirthDate { get; set; }

    public override string ToString()
    {
        return $"Name: {Name} | BirthDate: {BirthDate}";
    }
}
Enter fullscreen mode Exit fullscreen mode

Running the code

It's all we need to create the custom converter. Now we can just run the code and see the result.

Name: John | BirthDate: 1990-12-31 12:00:00 AM

Source

How to write custom converters for JSON serialization (marshalling) in .NET

Credits

Photo by James Harrison on Unsplash

Oldest comments (0)