4

When deserializing a JSON string with missing properties, those properties in my class are populated with their default values. I want to change the JsonSerializerSettings so that, if a property is missing in the JSON and not nullable in the class, an exception is thrown. Conversely, when a property is nullable, it's not required.

I know it's possible with attributes but I want a generic setting.

JsonSerializerSettings settings = new JsonSerializerSettings();
MyParameters parms = JsonConvert.DeserializeObject<MyParameters>(json, settings);

Example:

public class MyParameters
{
    public string Message1 { get; set; }
    public string Message2 { get; set; }
    public int MyInt { get; set; }
    public int? MyNullableInt { get; set; }
}

The following JSON should be deserializable:

{
    "Message1": "A message",
    "MyInt ": 1
}

As result:

Message1 = "A message"
Message2 = null
MyInt = 1
MyNullableInt = null

But the following JSON should cause an exception because MyInt is missing:

{
    "Message1": "A message",
    "MyNullableInt": 1
}
Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
Boomit
  • 147
  • 1
  • 6
  • @LasseVågsætherKarlsen That's not what I'm asking, I explicit said that I don't want to use attributes + when an property is nullable, I dont want it to be required so I can't use `settings.MissingMemberHandling = MissingMemberHandling.Error;` – Boomit Aug 27 '19 at 11:41
  • MissingMemberHandling only works if you have a property in the json that doesn't exist on your type, not for your case. As far as I know, other than the required attribute, there is no other way of handling this. Let me rephrase that. All the ways I know how to handle this case involves changing the type you deserialize into. You don't want to do that so then I think you're out of luck. Hopefully someone will prove me wrong. – Lasse V. Karlsen Aug 27 '19 at 11:53
  • Can you simply decorate `MyInt` with: `[JsonProperty(Required = Required.Always)]`? The base converter will throw when that property is not part of the JSON. – Jimi Aug 27 '19 at 13:52

1 Answers1

2

You can use a custom ContractResolver to do what you want:

class NonNullablePropertiesRequiredResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty prop = base.CreateProperty(member, memberSerialization);
        Type propType = prop.PropertyType;
        if (propType.IsValueType && !(propType.IsGenericType && propType.GetGenericTypeDefinition() == typeof(Nullable<>)))
        {
            prop.Required = Required.Always;
        }
        return prop;
    }
}

Apply the resolver to your JsonSerializerSettings like this when you deserialize:

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new NonNullablePropertiesRequiredResolver();
MyParameters parms = JsonConvert.DeserializeObject<MyParameters>(json, settings);

Working demo: https://dotnetfiddle.net/t56U2a

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