3

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 ?

Oyvind
  • 487
  • 1
  • 6
  • 21
  • Did you try to reach the docs? – Pavel Anikhouski Feb 01 '21 at 12:57
  • 1
    Looks like this is not available out of the box. [JsonConverterAttribute](https://docs.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonconverterattribute?view=net-5.0) has nothing similar to ConverterParameters. The [migration guide](https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to) doesn't even mention compile-time converter attributes. You may need to subclass your `MyDecimalConverter` as needed, say `MyDecimalConverter3Digit`. – dbc Feb 01 '21 at 17:23
  • I can imagine workarounds if you were applying the converter to the type rather than to the property, but I don't see any way for the converter to know the property to which it was applied. – dbc Feb 01 '21 at 17:24
  • @PavelAnikhouski yeah, did you ? – Oyvind Feb 01 '21 at 21:54
  • 1
    @dbc yep, that's my conclusion too so far. A little less elegant though.. – Oyvind Feb 01 '21 at 21:55

1 Answers1

2

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.

enter image description here

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());
        }); 

After that you could use it in the model, like this:

public class Calculate
{
    public decimal Price { get; set; }
    [JsonConverter(typeof(MyDecimalConverter3Digit))]
    public decimal Rate { get; set; }
}

Besides, you could also configure your application to use the Newtonsoft.Json serialize and deserialize json. Please refer the following steps:

  1. Install the Microsoft.AspNetCore.Mvc.NewtonsoftJson package via NuGet or use the following command:

     Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson
    
  2. 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:

    enter image description here

    After that, you could use the custom converter with parameters.

Zhi Lv
  • 15,351
  • 1
  • 10
  • 21
  • This is the obvious way of doing it (and what I ended up doing). It does not answer the question though, and making concrete classes for each number of decimals is not very elegant in my opinion. Also, Newtownsoft is deprecated, as System.Text.Json [is the new way](https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to?pivots=dotnet-5-0) of doing this. Configuring the application with legacy libraries is very likely to cause problems later on. – Oyvind Feb 02 '21 at 07:37
  • Hi @Oyvind, Yes, you are right. But, at present the `System.Text.Json` doesn't allow to add parameters, you could consider using above method as a temporary workaround, and you can also consider [filing an issue](https://github.com/dotnet/runtime/issues/new) to find out if support for your scenario can be added. – Zhi Lv Feb 02 '21 at 07:57
  • *After that you could use it in the model...* You don't need to register the converter with `Startup.ConfigureServices` in order to apply it to the model. Converters applied directly to properties take precedence as explained in [Converter registration precedence](https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to?pivots=dotnet-5-0#converter-registration-precedence). – dbc Feb 02 '21 at 15:45