I also missed this feature from System.Text.Json.Serialization, and used to use a custom JsonConverter for every formatting case, but I really did not like. My best workorund to solve this a cleaner way - at least for my taste - uses a custom JsonConverterAttribute. I use this in .NET6 apps, but according to the docs, it works with the Core 3.1, too.
So the example: Create a Converter that requires a constructor parameter (based on the question that is done already). In my case it is the format string.
public class DoubleConverter : JsonConverter<double> { private readonly string _format; public DoubleConverter(string format) => _format = format; public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // Not needed for the example. throw new NotImplementedException(); } public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options) { writer.WriteStringValue(value.ToString(_format)); } }
Then create a custom JsonAttribute. This part makes the usage easy, because it accepts the needed constructor parameter, and creates the cutom JsonConverter using that parameter.
[AttributeUsage(AttributeTargets.Property)] public class DoubleSerializationStringFormatAttribute : JsonConverterAttribute { private readonly string _format; public DoubleSerializationStringFormatAttribute(string format) => _format = format; public override JsonConverter CreateConverter(Type typeToConvert) { if (typeToConvert != typeof(double)) { throw new ArgumentException( $"This converter only works with double, and it was provided {typeToConvert.Name}."); } return new DoubleConverter(_format); } }
Now the attribute can be used on any property:
public class DataClass { [DoubleSerializationStringFormat("N2")] public double Prop1 { get; set; } [DoubleSerializationStringFormat("N5")] public double Prop2 { get; set; } }
Finally I can serialize the DataClass instance:
var data = new DataClass() {Prop1 = 10.5678, Prop2 = 3.14159267}; var serialized = JsonSerializer.Serialize(data); Console.Write(serialized);
And I get the numbers serialized according to the specified format:
{ "Prop1":"10.57", "Prop2":"3.14159" }
MyDecimalConverteras needed, sayMyDecimalConverter3Digit.