72

I'm trying to deserialize some JSON objects using Json.NET. I've found however that when I deserialize an object that doesn't have the properties I'm looking for that no error is thrown up but a default value is returned for the properties when I access them. It's important that I'm able to detect when I've deserialized the wrong type of object. Example code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace Json_Fail_Test
{
    class Program
    {
        [JsonObject(MemberSerialization.OptOut)]
        private class MyJsonObjView
        {
            [JsonProperty("MyJsonInt")]
            public int MyJsonInt { get; set; }
        }

        const string correctData = @"
        {
            'MyJsonInt': 42
        }";

        const string wrongData = @"
        {
            'SomeOtherProperty': 'fbe8c20b'
        }";

        static void Main(string[] args)
        {
            var goodObj = JsonConvert.DeserializeObject<MyJsonObjView>(correctData);
            System.Console.Out.WriteLine(goodObj.MyJsonInt.ToString());

            var badObj = JsonConvert.DeserializeObject<MyJsonObjView>(wrongData);
            System.Console.Out.WriteLine(badObj.MyJsonInt.ToString());
        }
    }
}

The output of this program is: 42 0

I would prefer an exception be thrown to failing silently. Short of that is there a way to detect if the serialization failed to find a parameter?

I know I can parse the data with a Json object and then check for the parameter with a key value lookup but the codebase I'm in uses the pattern above and I'd like keep that consistent if it's possible.

knocte
  • 16,941
  • 11
  • 79
  • 125
DubiousPusher
  • 1,132
  • 2
  • 8
  • 19

5 Answers5

84

The Json.Net serializer has a MissingMemberHandling setting which you can set to Error. (The default is Ignore.) This will cause the serializer to throw a JsonSerializationException during deserialization whenever it encounters a JSON property for which there is no corresponding property in the target class.

static void Main(string[] args)
{
    try
    {
        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.MissingMemberHandling = MissingMemberHandling.Error;

        var goodObj = JsonConvert.DeserializeObject<MyJsonObjView>(correctData, settings);
        System.Console.Out.WriteLine(goodObj.MyJsonInt.ToString());

        var badObj = JsonConvert.DeserializeObject<MyJsonObjView>(wrongData, settings);
        System.Console.Out.WriteLine(badObj.MyJsonInt.ToString());
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.GetType().Name + ": " + ex.Message);
    }
}

Result:

42
JsonSerializationException: Could not find member 'SomeOtherProperty' on object
of type 'MyJsonObjView'. Path 'SomeOtherProperty', line 3, position 33.

See: MissingMemberHandling setting.

dbc
  • 104,963
  • 20
  • 228
  • 340
Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
  • I actually found the settings class digging through the documentation but I must have skimmed over that property. I'm kind of a crap speed reader. Thanks so much; this is perfect. – DubiousPusher Jan 09 '14 at 22:16
  • @BrianRogers Thank you. It helped me alot. Do have any link to share on further studying JSON parsing, esp the missing and Null value handling issues? – Anoop Chandrika HarisudhanNair Dec 01 '14 at 02:19
  • 1
    I have a quite similar problem. If one member of the target class is missing in the JSON, the deserializer will ignore it and set it to null. Even if the MissingMember setting is set to error. – Alu Sep 07 '15 at 12:33
  • 2
    Already found a solution. Used attributes to mark my members as required. – Alu Sep 07 '15 at 16:46
  • The example would be: deserializing an empty json string "{}" into any type. It will set all values in the type to null. But I want an exception if the type doesnt match the json. – Alu Sep 07 '15 at 16:52
27

Just add [JsonProperty(Required = Required.Always)] to the required properties and it'll throw exception if the property is not there while deserializing.

[JsonProperty(Required = Required.Always)]
 public int MyJsonInt { get; set; }
GorvGoyl
  • 42,508
  • 29
  • 229
  • 225
  • 7
    This solves a complimentary problem. If your **model** has a property that your **JSON** does not, and you want that to be an error, use `[JsonProperty(Required = Required.Always)]`. See: [JsonPropertyAttribute required](https://www.newtonsoft.com/json/help/html/JsonPropertyRequired.htm). If your **JSON** has a property that your **model** does not, and you want that to be an error, use `MissingMemberHandling = MissingMemberHandling.Error`. – dbc Aug 05 '19 at 18:51
8

Put the following attribute on required properties:

[DataMember(IsRequired = true)]

If the member is not present, it will throw a Newtonsoft.Json.JsonSerializationException.

As Brian suggested below, you will also need this attribute on your class:

[DataContract]
Adam Modlin
  • 2,994
  • 2
  • 22
  • 39
  • Are you sure about this? I tried adding the attribute and no exception is given. And the program still prints 0. – DubiousPusher Jan 09 '14 at 21:56
  • 6
    This solution will only work if you have `[DataContract]` on your class AND you do NOT have `[JsonProperty]` on the member. (`JsonProperty` overrides `DataMember`.) You could, however, set the `Required` parameter on the `[JsonProperty]` attribute to `Required.Always` to accomplish the same thing. – Brian Rogers Jan 09 '14 at 22:27
  • @DubiousPusher properties should be nullable. then it will work. – afruzan Nov 11 '20 at 07:09
3

As @dbc tells in comments:

  • At deserialization:

If your Model has a property that your JSON does not, and you want that to be an error, use [JsonProperty(Required = Required.Always)].

  • At serialization:

If your JSON has a property that your Model does not, and you want that to be an error, use MissingMemberHandling = MissingMemberHandling.Error.

also using [DataMember(IsRequired = true)] for error at deserialization is true when proeprty type is nullable.

afruzan
  • 1,454
  • 19
  • 20
2

Just define your members in your definition class with a question mark '?' int?:

private class MyJsonObjView
{
    [JsonProperty("MyJsonInt")]
    public int? MyJsonInt { get; set; }
}

When it is not initialized, it will just be null, otherwise it will be a valid value. This allows you to have settings optional and evaluate them on a per-setting basis.

isgoed
  • 724
  • 6
  • 12