Reputation: 597
I wrote my own JsonConverter (using ASP.Net Core 3.1), which I intended to use on my DTOs.
In previous versions (Newtonsoft.Json
), you could add a constructor on the custom JsonConverter class, and specify parameters using JsonConverterAttribute:
[JsonConverter(typeof(MyDecimalConverter), 3)]
public decimal MyProp { get; set; }
However, after the migration to System.Text.Json.Serialization
, this option is not there anymore. The new JsonConverterAttribute simply does not have a constructor for it.
What is the new way of achieving this ?
Upvotes: 12
Views: 21175
Reputation: 21383
After comparing the JsonConverterAttribute definition in Newtonsoft.Json
and System.Text.Json.Serialization
, we can find that: when using the System.Text.Json.Serialization
, it doesn't allow to enter the converter parameters.
So, as dbc said, you could create a Custom JsonConverter to convert the decimal with 3 digits, like this:
public class MyDecimalConverter3Digit : JsonConverter<decimal>
{
public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
public override void Write(Utf8JsonWriter writer, decimal value, JsonSerializerOptions options)
{
writer.WriteStringValue(Decimal.Round(value, 3).ToString());
}
}
Then, register the JsonConverter in Startup.ConfigureServices method:
services.AddControllersWithViews().AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new MyDecimalConverter3Digit());
});
Alternatively, you can use it directly in the model via the JsonConverterAttribute
, like this:
public class Calculate
{
public decimal Price { get; set; }
[JsonConverter(typeof(MyDecimalConverter3Digit))]
public decimal Rate { get; set; }
}
(This takes precedence over any converters registered in the options.)
Besides, you could also configure your application to use the Newtonsoft.Json serialize and deserialize json. Please refer the following steps:
Install the Microsoft.AspNetCore.Mvc.NewtonsoftJson
package via NuGet or use the following command:
Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson
Add .AddNewtonsoftJson()
method at the end of the AddControllersWithViews()
, like this:
services.AddControllers().AddNewtonsoftJson();
services.AddControllersWithViews().AddNewtonsoftJson();
services.AddRazorPages().AddNewtonsoftJson();
When you create custom converter, remember to use the Newtonsoft reference, instead of System.Text.Json.Serialization
. Like this:
After that, you could use the custom converter with parameters.
Upvotes: 5
Reputation: 131
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"
}
Upvotes: 13