System.Text.Json – Apply a custom converter to a specific property

When you create a custom converter, you create it to handle a specific type (such as DateTime). When you add this converter to JsonSerializerOptions.Converters, it applies the converter to all properties of that type (i.e. all DateTime properties).

How about if you want to apply a custom converter to a specific property? To do that, you can use the JsonConverter attribute. For example, let’s say you have a custom converter called ExpirationDateConverter and you only want to apply it to the ExpirationDate property:

using System.Text.Json.Serialization; public class Product { [JsonConverter(typeof(ExpirationDateConverter))] public DateTime ExpirationDate { get; set; } public DateTime ManufacturedDate { get; set; } }
Code language: C# (cs)

During serialization / deserialization, it’ll create and use an ExpirationDateConverter object when handling the ExpirationDate property. Here’s a serialization example:

using System.Text.Json; var options = new JsonSerializerOptions() { WriteIndented = true }; var manufacturedDate = DateTime.Now; var product = new Product() { ExpirationDate = manufacturedDate.AddYears(2), ManufacturedDate = manufacturedDate }; var json = JsonSerializer.Serialize(product, options); Console.WriteLine(json);
Code language: C# (cs)

Here’s the JSON this produces:

{ "ExpirationDate": "2024-02", "ManufacturedDate": "2022-02-02T08:03:26.9510435-05:00" }
Code language: JSON / JSON with Comments (json)

It used ExpirationDateConverter to serialize the ExpirationDate property. This had no effect on the other DateTime property. This shows how you can apply a custom converter to one or more specific properties, instead of having to apply it to all properties with a specific type.

Specify custom converter parameters per property

JsonConverterAttribute only handles parameterless custom converters. To pass in property-specific configuration values to a custom converter, you have to create a custom attribute that subclasses JsonConverterAttribute. This custom attribute class has to create the custom converter object using the passed in configuration value.

I’ll show how to do this below by showing an example of using different date formats for each DateTime property.

1 – Create a parameterized custom converter

The following parameterized custom converter accepts a date format string in the constructor. It uses this format string in the Write() method (serialization) and in the Read() method (deserialization):

using System.Text.Json; using System.Text.Json.Serialization; public class CustomDateTimeConverter : JsonConverter<DateTime> { private readonly string Format; public CustomDateTimeConverter(string format) { Format = format; } public override void Write(Utf8JsonWriter writer, DateTime date, JsonSerializerOptions options) { writer.WriteStringValue(date.ToString(Format)); } public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return DateTime.ParseExact(reader.GetString(), Format, null); } }
Code language: C# (cs)

2 – Subclass JsonConverterAttribute

Create a custom attribute class that subclasses JsonConverterAttribute. Add constructor parameters and override the CreateConverter() method:

using System.Text.Json.Serialization; public class JsonCustomDateTime : JsonConverterAttribute { public readonly string Format; public JsonCustomDateTime(string format) { Format = format; } public override JsonConverter? CreateConverter(Type typeToConvert) { if (typeToConvert != typeof(DateTime)) throw new Exception("Can only use this attribute on DateTime properties"); return new CustomDateTimeConverter(Format); } }
Code language: C# (cs)

When the JsonSerializer encounters a property with the JsonCustomDateTime attribute, it’ll call CreateConverter(), which will return a CustomDateTimeConverter object. That will then be used to serialize / deserialize the property.

3 – Apply the custom attribute to properties

Add the custom attribute to the DateTime properties and specify the date format for each property:

public class Product { [JsonCustomDateTime("yyyy-MM")] public DateTime ExpirationDate { get; set; } [JsonCustomDateTime("yyyy-MM-dd")] public DateTime ManufacturedDate { get; set; } }
Code language: C# (cs)

4 – Serialization example

Serialize the Product object:

using System.Text.Json; var manufacturedDate = DateTime.Now; var product = new Product() { ExpirationDate = manufacturedDate.AddYears(2), ManufacturedDate = manufacturedDate }; var json = JsonSerializer.Serialize(product); Console.WriteLine(json);
Code language: C# (cs)

Here’s the JSON produced:

{"ExpirationDate":"2024-02","ManufacturedDate":"2022-02-02"}
Code language: JSON / JSON with Comments (json)

Leave a Comment