Thursday, December 26, 2019

Globally configuring values for JSON Serializer in ASP.NET Core 3.1

This article will focus on how one can set certain constraints on the given data type for JSON serialization and that too at the application level, which means changes need to be done at a global level rather than doing for specific custom class or property. We will also see, how one can fallback to default settings, post this application level change.
Let’s understand this with the help of an example.
Making application level changes for JSON serialization
Here problem statement is, we want all the float values to be restricted to 3 decimal places. Now, one way to achieve this is to decorate all the float properties in all the model classes with specific attribute using [JsonConverter(typeof(…)].
With above attribution, one can indeed achieve the goal of conversion or data formatting, but what if there are so many float values across the application. Is it feasible to go and change each and every single float property under every model class? I feel, NO :(

So, the solution to this problem is to do such setting globally and this can be achieved in two steps, wherein first step we will introduce a class which will take care of conversion or data formatting stuff and in second step we will associate this class with ASP.NET Core services. Here is the code:
Model class:
public class Calculate
{
  public float Price { get; set; }
  public float Rate { get; set; }
}
Converter class:
public class FloatConverter : JsonConverter
{
  public override float Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
  {
    throw new NotImplementedException();
  }
  public override void Write(Utf8JsonWriter writer, float value, JsonSerializerOptions options)
  {
    writer.WriteStringValue(string.Format("{0:F3}", value));
  }
}

and then few code changes in Startup class is as follows: 
public void ConfigureServices(IServiceCollection services)
{
  ...
  services.AddControllersWithViews().AddJsonOptions(options =>
    {
       options.JsonSerializerOptions.Converters.Add(new FloatConverter());
    });
}

Now, if you will run your application, you will notice that all the floats came out of JSON serialization are shown till 3 decimal places.

Fallback to default settings
Now let's say, there are few float properties in our model class, on which we don't want to apply this global setting. Now, how to solve this?

Well, to make the default settings work, we have to create another converter which will override the global setting and then decorate all those properties with this new converter. This new converter will do nothing more than retaining the default behavior. In our example, I don't want to apply any conversion logic for Rate property. So, this is how we can change our model class: 

public class Calculate
{
  public float Price { get; set; }
  [JsonConverter(typeof(DefaultFloatConverter))]
  public float Rate { get; set; }
}
and code for DefaultFloatConverter is as follows:
public class DefaultFloatConverter : JsonConverter
{
  public override float Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
  {
   throw new NotImplementedException();
  }
  public override void Write(Utf8JsonWriter writer, float value, JsonSerializerOptions options)
  {
    writer.WriteNumberValue(value);
  }
}

Now, if you will run the application, you will notice that Rate is coming in it's default precision whereas Price is restricted to 3 decimals.

Hope you enjoyed reading.

No comments:

Post a Comment