1

Is it possible to have JObject.Parse ignore missing fields?

From my example below you can see that I have declared a class Address and using JsonProperty to specifying alternate field names.

I have provided 3 examples, there are 3 JSON strings which have a slightly different structure, only Example 1 matches and returns an object, Examples 2 and 3 return a null because there is a missing field.

Is there a way to use other JsonProperty's to allow them to be ignored if not provided?

public class Address
{
    [JsonProperty("flat_number")]
    public string FlatNumber { get; set; }

    [JsonProperty("house_number")]
    public string HouseNumber { get; set; }

    [JsonProperty("address")]
    public string Address1 { get; set; }

    [JsonProperty("address2")]
    public string Address2 { get; set; }

    [JsonProperty("town")]
    public string Town { get; set; }

    [JsonProperty("postcode")]
    public string Postcode { get; set; }
}

private static T TryParse<T>(string json) where T : new()
{
    var jSchemaGenerator = new JSchemaGenerator();

    const string license = "license";

    License.RegisterLicense(license);

    var jSchema = jSchemaGenerator.Generate(typeof(T));

    var jObject = JObject.Parse(json);

    return jObject.IsValid(jSchema) ? JsonConvert.DeserializeObject<T>(json) : default(T);
}

//Example 1 with house_number and flat_number
const string json = "{\"house_number\":\"40\",\"flat_number\":\"82\",\"address\":\"Somewhere\",\"address2\":\"Over\",\"town\":\"There\",\"postcode\":\"ZZ991AA\"}";

//Example 2 with house_number but not flat_number
//const string json = "{\"house_number\":\"40\",\"address\":\"Somewhere\",\"address2\":\"Over\",\"town\":\"There\",\"postcode\":\"ZZ991AA\"}";

//Example 3 with flat_number but not house_number 
//const string json = "{\"flat_number\":\"82\",\"address\":\"Somewhere\",\"address2\":\"Over\",\"town\":\"There\",\"postcode\":\"ZZ991AA\"}";

var tryParse = TryParse<AddressTest>(json);

if (tryParse != null)
{

}
Anas Alweish
  • 2,818
  • 4
  • 30
  • 44
iggyweb
  • 2,373
  • 12
  • 47
  • 77

3 Answers3

2

You can use JsonSerializerSettings to perform this operation. This will ignore your missing members.

var jsonSerializerSettings = new JsonSerializerSettings();
jsonSerializerSettings.MissingMemberHandling = MissingMemberHandling.Ignore;

JsonConvert.DeserializeObject<YourClass>(jsonResponse, jsonSerializerSettings);
Hamza Haider
  • 730
  • 6
  • 20
  • Thank you for your reply, I modified my code as per your suggestion `var jsonSerializerSettings = new JsonSerializerSettings {MissingMemberHandling = MissingMemberHandling.Ignore}; return jObject.IsValid(jSchema) ? JsonConvert.DeserializeObject(json, jsonSerializerSettings) : default(T);` but unfortunately Examples 2 and 3 still return a null. – iggyweb Oct 30 '18 at 11:37
  • May be the problem is in your data jObject.IsValid(jSchema) otherwise this method works well. – Hamza Haider Oct 30 '18 at 12:28
0

If you json contains some key/value pair as dynamic means you don't know if these key/value pairs is exist in json or not

If your objects are not fixed and data must be configurable then Newtonsoft.json has one feature that to be use here and that is [JsonExtensionData]. Read more

Extension data is now written when an object is serialized. Reading and writing extension data makes it possible to automatically round-trip all JSON without adding every property to the .NET type you’re deserializing to. Only declare the properties you’re interested in and let extension data do the rest.

Now your house_number and flat_number will be collected in [JsonExtensionData] so you no need to handle missing fields anymore.

So your Address class will be

public class Address
{
    [JsonExtensionData]
    public IDictionary<string, JsonToken> extensionData { get; set; }

    [JsonProperty("address")]
    public string Address1 { get; set; }

    [JsonProperty("address2")]
    public string Address2 { get; set; }

    [JsonProperty("town")]
    public string Town { get; set; }

    [JsonProperty("postcode")]
    public string Postcode { get; set; }
}
er-sho
  • 9,581
  • 2
  • 13
  • 26
  • Thank you for your reply, can I assume from your example that the json string structure would need to change? If so I have no say over the structure of the json string received. However I have found a resolution to my issue, thank you for taking the time to help. – iggyweb Oct 30 '18 at 12:07
  • no your json structure will remain as it is, no any other side effect to your json.. all the three example you listed in question will properly deserialized successfully. – er-sho Oct 30 '18 at 12:09
-1

After a little more digging I found a JsonProperty that allows nulls to be ignored, by applying NullValueHandling = NullValueHandling.Ignore to both FlatNumber and HouseNumber all examples return an object. Therefore modifying the Address class as per my example below works in conjunction with my original code.

public class Address
{
    [JsonProperty("flat_number", NullValueHandling = NullValueHandling.Ignore)]
    public string FlatNumber { get; set; }

    [JsonProperty("house_number", NullValueHandling = NullValueHandling.Ignore)]
    public string HouseNumber { get; set; }

    [JsonProperty("address")]
    public string Address1 { get; set; }

    [JsonProperty("address2")]
    public string Address2 { get; set; }

    [JsonProperty("town")]
    public string Town { get; set; }

    [JsonProperty("postcode")]
    public string Postcode { get; set; }
}
iggyweb
  • 2,373
  • 12
  • 47
  • 77