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"}
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}";
}
}
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)
{
}
}
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);
}
}
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>
{
}
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();
}
}
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();
}
}
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}";
}
}
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
Top comments (0)