3

I am using JsonConvert.DeserializeObject(json.ToString()); to deserialise a JSON and populate my fields in a related model. This works well until there is data missing in the JSON. Basically instead of having "key : value" I will just have "key : null".

My understanding about the JsonConverter was that it would create an object, in which I should be able to populate fields with a default value either through the constructor (not being called in my case for unknown reasons), or through the tags as mentioned here: Default value for missing properties with JSON.net or here: Why when I deserialize with JSON.NET ignores my default value?

I have tried both and neither results in the related fields being initialised. Of course if there is no data in the JSON, nothing can be deserialised to the related model. However I would expect that I still could initialise some values with defaults, which would then just be ignored (not overwritten) by JsonConverter (just like what happens now). This however, does not seem to be possible?

Source code of previous attempts

Model class

namespace Project.MyJob
{
    public class JsonModel
    {
        public JsonModel()
        {
            Type_X type_x = new Type_X();
            // This is not doing anything. I would have expected that the 
            // class' constructor would be called but, no.
        }
        public string objectNumber { get; set; }
        public string objectFamily { get; set; }
        public string objectOrder { get; set; }
        public string location { get; set; }
        public string place { get; set; }
        public string inventionTime { get; set; }
        public string lastUpdate { get; set; }
        public string condition { get; set; }

        public Type_X Type_X { get; set; }
        public List<Actions> actions { get; set; }         
    }

    public class Actions
    {
        public string count { get; set; }
        public string datetime { get; set; }
        public string place { get; set; }
        public string status { get; set; }
    }

    public class Type_X
    {  

        public Type_X
        {
          // This should be executed when a new Type_X object is created? Also 
          // not.
          partA = "null";
        }

        [DefaultValue("null")]
        [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
        public string partA { get; set; }

        // Trying public string partA { get; set; } = "null"; also does 
        // nothing.

        [DefaultValue("null")]
        [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
        public string PartB { get; set; }

        [DefaultValue("null")]
        [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
        public string partC { get; set; }

        [DefaultValue("null")]
        [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
        public string partD { get; set; }

        [DefaultValue("null")]
        [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
        public string partE { get; set; }
    }
}

Creation of JSON object with default values (defaults not working)

JObject = JsonConvert.DeserializeObject<JsonModel>(json.ToString(), new 
JsonSerializerSettings {DefaultValueHandling = 
DefaultValueHandling.Populate});

Example of downstream usage of the created objects

JObject.actions[i].count + "more text"

Above works when not relying on defaults.

Just_Stacking
  • 395
  • 3
  • 13
  • 4
    You say you have "key": null in your JSON. That is really different from it being not there at all. null is a valid value, so it gets assigned. I would say that default values only kick in, if the key is missing completely from the JSON. And why do you think that the constructor is not called. Have you set a breakpoint there? – Daniel Hilgarth Dec 21 '17 at 08:51
  • 2
    Leading on from what @Daniel said, `JsonSerializerSettings` has a `NullValueHandling` property. – ProgrammingLlama Dec 21 '17 at 08:53
  • Ah, interesting insight. I will try to remove this trailing data set from my json to see what happens. – Just_Stacking Dec 21 '17 at 08:54

1 Answers1

11

You are using the wrong setting.

If you want null values in the JSON to be ignored during deserialization, you need to set NullValueHandling = NullValueHandling.Ignore in the settings. The default is Include, which means that if the JSON has an explicit null in it for a particular property, that property will be set to null on your object, overwriting any default you may have set.

DefaultValueHandling.Populate means if the key is missing altogether in the JSON (which is different from being set to null), then it will use the value provided by the [DefaultValue] attribute. Note that if the JSON has an explicit null in it, this setting will not use the default value from the attribute, even if NullValueHandling is set to Ignore. So if you want a default value in that situation, the best way to do that is by setting it in the constructor.

So, in short, to get the behavior you want:

  • Use the NullValueHandling.Ignore setting.
  • Provide your default values via the constructor.
  • You don't need the DefaultValueHandling setting or the [DefaultValue] attribute.

Demo fiddle: https://dotnetfiddle.net/kyUjFz

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300