Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I deserialize a missing property to a default value in Json.NET?

Tags:

json.net

I have a class that is annotated with DataContract and DataMember attributes. Some members are marked as DataMember(IsRequired = true). When I serialize instances over the wire from Json.NET, and the required object members have null value, then their serialized values are missing in the output (which is apparently equivalent to being null in JSON). I'm okay with that.

I've created a sort of "echo" service which returns data sent to it as a response. So this service receives the JSON with missing members (or null members depending on how you look at it), and then sends it right back to my Json.NET client. The JSON on the wire looks the same in both directions as viewed through Fiddler (a proxy sniffer). So far so good.

When the original Json.NET sender receives the JSON response to deserialize it, the serializer throws an exception about not finding required members in the JSON payload:

Required property 'IAmRequired' not found in JSON. Path ''.

That is unfortunate, as the serializer is thus not able to deserialize data that it had previously serialized without a problem.

Short of changing the DataContract class to make the member not required (which I do not want to do for a number of reasons), is there a way to make Json.NET deserialize missing members to default values such as null?

Here is my deserialization code:

HasRequired h = null;
JObject json = response as JObject; // hand waving here
try
{
    JsonSerializer ser = new JsonSerializer();
    ser.MissingMemberHandling = MissingMemberHandling.Ignore; // doesn't seem to help
    ser.DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate; // doesn't seem to help
    ser.NullValueHandling = NullValueHandling.Include; // doesn't seem to help
    h = json.ToObject<HasRequired>(ser);
}
catch (Exception ex)
{
    // bummer, missing required members still
}
like image 464
Greg Avatar asked Dec 17 '14 22:12

Greg


People also ask

How do I deserialize an object in JSON?

A common way to deserialize JSON is to first create a class with properties and fields that represent one or more of the JSON properties. Then, to deserialize from a string or a file, call the JsonSerializer. Deserialize method.

What is the difference between serialize and deserialize JSON?

JSON is a format that encodes objects in a string. Serialization means to convert an object into that string, and deserialization is its inverse operation (convert string -> object).

What is JsonSerializer deserialize?

Serialization and deserialization in . NET application, JSON data format conversion to . NET objects and vice versa is very common. Serialization is the process of converting . NET objects such as strings into a JSON format and deserialization is the process of converting JSON data into . NET objects.

What is MissingMemberHandling?

MissingMemberHandling Property. Gets or sets how missing members (e.g. JSON contains a property that isn't a member on the object) are handled during deserialization. The default value is Ignore. Namespace: Newtonsoft.Json.


1 Answers

If you have properties marked with [DataMember(Required = true)] and you want to override the required behavior, there are a couple of things you can do:

  1. You can mark those same properties with [JsonProperty(Required = Required.Default)]. This works because [JsonProperty] takes precedence over [DataMember] in Json.Net.

    [DataContract]
    public class HasRequired
    {
        [DataMember(Required = true)]
        [JsonProperty(Required = Required.Default)]
        public string IAmRequired { get; set; }
    }
    
  2. Or, you can create a custom ContractResolver that programmatically sets Required = Required.Default on every property.

    class CustomResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            JsonProperty prop = base.CreateProperty(member, memberSerialization);
            prop.Required = Required.Default;
            return prop;
        }
    }
    

    To use the resolver, simply set the ContractResolver property on the serializer to a new instance of the custom resolver:

    JsonSerializer ser = new JsonSerializer();
    ser = new CustomResolver();
    
like image 89
Brian Rogers Avatar answered Oct 15 '22 08:10

Brian Rogers