Search code examples
c#jsonconverters

C# Newtonsoft: Override Constructor Default Value When Deserializing


I have some fairly complex JSON and need to use Newtonsoft to deserialize, as System.Text.Json is not as extensible as Newtonsoft.

My problem is as follows: I have a class, let's call "A", which I use a few places in my app including saving to a DB using EFCore and converting to a binary file. I populate the class using a JSON File, but due to requirements beyond my control I need to keep the default value setter in the class. However, IF the property does NOT exist in the Json we are deserializing, I'd like to use a custom default value.

Example Class:

public class A
{
  public int Id { get; set; } = 0;
  public bool IsRequired { get; set; } = true;
}

And if this is my Json:

[{
  "id": 4,
  "isRequired": true;
},
{
  "id": 7
}]

I'd like to override the isRequired default to false if the key is not in the json.

var list = JsonConvert.DeserializeObject<List<A>>( -- some settings --);
// list[0]
//  - Id = 4
//  - IsRequired = true
//
// list[1]
//  - Id = 6
//  - IsRequired = false

I've been able to get a basic version of this working as described in this SO post, but the deserialization is very simple and breaks immediately with nested properties and complex types + my custom contract resolver I have.

Note that I am using .NET 6, and my models are separated from my deserializers.


Solution

  • You just can add a json constructor to your class. You don't need to put all properties in the constructor, only those properties that behavier the special way

    public class A
    {
        public int Id { get; set;} = 0;
        public bool IsRequired { get; set; } = true;
       
        [JsonConstructor]
        public A (bool? isRequired) 
        {
          this.IsRequired = isRequired ?? false;
        }
    }
    

    test

    var list = JsonConvert.DeserializeObject<List<A>>(json);
    
    json=JsonConvert.SerializeObject(list, Newtonsoft.Json.Formatting.Indented);
    
    

    result

    [
      {
        "Id": 4,
        "IsRequired": true
      },
      {
        "Id": 7,
        "IsRequired": false
      }
    ]