3

I have a requirement where I need to set default value to the below complex property Instances using JsonProperty and DefaultValue.

I know we can achieve this for primitive properties as mentioned in the below link, but need to know how we can do it for complex properties.

Default value for missing properties with JSON.net

Below is the default Instances value I need to set using DefaultValue(). Please let me know how to achieve this.

Default value to be set to Instances property:

Instance instance = new Instance();
instance.Name = "XYZ";
instance.MyProperty = 11;

List<Instance> Instances = new List<Instance>();
Instances.Add(instance);

Code snippet:

public class DataSettings
{
  public DataSettings()
  {
    Instances = new List<Instance>();
  }

  [DefaultValue()] //How can I mention the above default value here ?
  [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
  public List<Instance> Instances { get; set; }
}

public class Instance
{
  public string Name { get; set; }
  public int MyProperty { get; set; }
}
Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
Vinay Gangaraj
  • 111
  • 1
  • 8

1 Answers1

2

As you've seen, attributes only support constant values, so you cannot set a complex value in an attribute. If you want to set a default value for a complex property during deserialization, a good approach is to use a serialization callback method, as shown below.

The idea is to add a method to your class which the serializer will call after deserialization is complete for the object. The callback must be a void method that accepts a StreamingContext as its only parameter, and it must be marked with an [OnDeserialized] attribute. The name of the method does not matter. Inside the callback method you can check whether the Instances list was populated, and if not, you can set the default value as you require.

public class DataSettings
{
    public DataSettings()
    {
        Instances = new List<Instance>();
    }

    public List<Instance> Instances { get; set; }

    [OnDeserialized]
    internal void SetDefaultValuesAfterDeserialization(StreamingContext context)
    {
        if (Instances == null || !Instances.Any())
        {
            Instances = new List<Instance>
            {
                new Instance { Name = "XYZ", MyProperty = 11 }
            };
        }
    }
}

Here is a working fiddle to demonstrate the concept: https://dotnetfiddle.net/uCGP5X

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
  • Thanks Brian, but there is one more issue with the above approach right ? If I add your logic in the constructor then if I explicitly create an object of DataSettings then by default Instances will have one value added in it's list right? For example what if I am creating an instance of DataSettings and I am adding below code then I will end up creating 2 values for Instances one from the Constructor logic and another which I am creating explicitly. DataSettings dataSettings = new DataSettings(); dataSettings.Instances.Add(new Instance() { Name = "XYZ" } ); – Vinay Gangaraj Mar 25 '21 at 08:40
  • 1
    I see. So you only want the default to be populated on deserialization but at no other time. In that case, using a deserialization callback is a much better approach. I've revised my answer. – Brian Rogers Mar 25 '21 at 16:10
  • Thanks Brian Rogers for your updated response. Is there any possibility where I can make use of JsonCustomConverter where we can pass default instance so that during deserialization it should check like if certain property of the object is null or entire object is null then use the default instance and return that instance back. Just curious know if there is any ? – Vinay Gangaraj Apr 05 '21 at 15:05