0

When deserializing a JSON object with nested objects, with a required property on one of the nested objects, Deserialize does not throw an Exception. But if I add the JsonProperty.Required decoration to the base object, it does (as I'd expect). This happens when the input string is the entirely wrong type, but is properly formatted JSON.

So, the problematic input is "{\"Errors\":[\"This is an error\"]}" (which is the response from a webservice, either it's an array of error messages like this, or it's a properly serialized UserInformationRequest). Code to clarify:

Base Object JsonProperty functioning properly:

    public class UserInformation
    {
        public string ID;
        ...
        public string LoginName;
        ...
    }

    public class UserInformationRequest
    {
        [JsonProperty(Required = Required.Always)]
        public string TimeStamp;
        public UserInformation User;
    }
    ...
    public static UserInformationRequest GetUserInformationRequestFromString(string userInformation)
    {
        try
        {
            return JsonConvert.DeserializeObject<UserRequestInformation>(userInformation);
        }
        catch (Exception ex)
        {
            //exception thrown when userInformation.TimeStamp is null, as expected
            return null;
        }
    }

Nested JsonProperty not functioning properly:

    public class UserInformation
    {
        public string ID;
        ...
        [JsonProperty(Required = Required.Always)]
        public string LoginName;
        ...
    }

    public class UserInformationRequest
    {
        public string TimeStamp;
        public UserInformation User;
    }
    ...
    public static UserInformationRequest GetUserInformationRequestFromString(string userInformation)
    {
        try
        {
            return JsonConvert.DeserializeObject<UserRequestInformation>(userInformation);
        }
        catch (Exception ex)
        {
            //never gets here - no exception thrown if userInformation.User.LoginName is null
            return null;
        }
    }

Given this, when attempting to deserialize the Errors array into the UserInformationRequest, an exception is properly thrown if there is a JsonProperty on the base object, but it is never thrown if the nested object contains a JsonProperty.

Working dotnetfiddles demonstrating the issue: JsonProperty on base object: https://dotnetfiddle.net/qvyPfP JsonProperty on nested object: https://dotnetfiddle.net/M3F0rb

6
  • Could you show the "userInformation" json string received as parameter in the "GetUserInformationRequestFromString" method please ? Commented Jul 29, 2017 at 14:39
  • @emkayultra, in what version(s) of .Net and Json.Net are you seeing this issue? Commented Jul 29, 2017 at 14:41
  • @JonLopezGarcia - first example: "{\"TimeStamp\":null,\"User\":{\"ID\":12345,\"LoginName\":\"username\"}}"} AND second example: "{\"TimeStamp\":\"2017-07-29 10:31:53\",\"User\":{\"ID\":12345,\"LoginName\":null}}" Commented Jul 29, 2017 at 14:46
  • @AlDass - .NET 4.5, Json.NET 10.0.3 Commented Jul 29, 2017 at 14:47
  • I'm updating the question, because after digging it's a little more complicated than that. Commented Jul 29, 2017 at 14:59

1 Answer 1

2

If you also mark, your User property in the UserInformationRequest class with the [JsonProperty(Required = Required.Always)] attribute, the deserializer seems to look inside the UserInformation for the LoginName member to be not null as requested.

Here you have your second example with the attribute on the User property

Sign up to request clarification or add additional context in comments.

3 Comments

That looks like it does sort of address the issue. However, what if I don't want User to be required, but if User does happen to be supplied, then it has to have LoginName
Well, if we consider carefully, it is exactly what happens. If you supply a User property and the required attribute is on the LoginName property, an exception will be raised. See here. If you don't supply nothing about an User property in the json string, the deserializer will completely ignore the field in the class. If you don't want the behavior to be so, and force the deserializer to look after an User property in the json, it means that you want the field to be fill out (in other words, to be required). Use required attribute
That makes sense, thank you for your help and clarification. Marking your answer as "the" answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.