Newtonsoft.json: Handling duplicate elements in JSON payload

Created on 6 Jun 2016  ·  17Comments  ·  Source: JamesNK/Newtonsoft.Json

What is the best way with Json.NET to restrict occurrence of duplicate elements in JSON payload?
For example:
{
"role" : "default",
"username" : "mallory",
"role": "admin",
"password" : "Evil123!"
}

Most helpful comment

@JamesNK My team would really like to be able to detect this case. Would you be amenable to a PR that adds a new JsonSerializerSettings option for switching between the current "accept last" behavior and "emit parse error" behavior?

All 17 comments

I would like to know how to do this using the JSON.NET schema library as well.

According to the spec as well:

2.2. Objects

An object structure is represented as a pair of curly brackets
surrounding zero or more name/value pairs (or members). A name is a
string. A single colon comes after each name, separating the name
from the value. A single comma separates a value from a following
name. The names within an object SHOULD be unique.

  object = begin-object [ member *( value-separator member ) ]
  end-object

  member = string name-separator value

You will need to use JsonTextReader

We tried that. The text reader does not restrict duplicates, in fact it
seems to allow them and uses the last property/value combination specified.
On Jun 6, 2016 5:28 PM, "James Newton-King" [email protected]
wrote:

You will need to use JsonTextReader


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/JamesNK/Newtonsoft.Json/issues/931#issuecomment-224093989,
or mute the thread
https://github.com/notifications/unsubscribe/AEXsnAuZRa6o5Bd4mTLbt_twpIwhuIjNks5qJJEDgaJpZM4IvInf
.

Oh I misunderstood. There is no way in Json.NET to restrict them. It will use the last value.

Seeing as the JSON spec indicates valid JSON should contain unique names
within an object it seems like this should be a feature of the
validation/schema library of JSON.NET? Perhaps a feature request is in
order?
On Jun 6, 2016 6:09 PM, "James Newton-King" [email protected]
wrote:

Oh I misunderstood. There is no way in Json.NET to restrict them. It will
use the last value.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/JamesNK/Newtonsoft.Json/issues/931#issuecomment-224104005,
or mute the thread
https://github.com/notifications/unsubscribe/AEXsnNF-j9VzoT7x5IHyUAEzMosVJL1-ks5qJJqngaJpZM4IvInf
.

        {
            var message =   "{" +
                                "\"DeviceAdded\" :" + 
                                "{" +
                                    "\"DeviceId\" : \"SN123456\"," +
                                    "\"Protocols\" : []," +
                                    "\"DeviceType\" : \"UPS\"," +
                                    "\"Model\" : \"12345\"," +
                                    "\"HardwareVersion\" : \"1.0.0.0\"," +
                                    "\"FirmwareVersion\" : \"2.0.0.0\"," +
                                    "\"SoftwareVersion\" : \"3.0.0.0\"," +
                                    "\"SerialNumber\" : \"1\"," +
                                    "\"SerialNumber\" : \"456\"" +
                                "}" +
                            "}";

            var jobj = JsonConvert.DeserializeObject<JObject>(message);
            Console.WriteLine(jobj);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.GetType());
            Console.WriteLine(ex.Message);
        }

If I use Newtonsoft.Json 6.0.8 I get exception System.ArgumentException: Can not add property SerialNumber to Newtonsoft.Json.Linq.JObject. Property with the same name already exists on object.

If I use Newtonsoft.Json 8.0.2 the code executes without error. What changed between these two versions? How with Newtonsoft.Json 6.0.8 I can get the same behavior as with Newtonsoft.Json 6.0.8?

What changed between these two versions? How with Newtonsoft.Json 6.0.8 I can get the same behavior as with Newtonsoft.Json 6.0.8?

A lot I suspect. You've accidentally specified the same version twice in your sentence. Are you trying to get 8.0.2 to behave like 6.0.8, or make 6.0.8 behave like 8.0.2?

I would like 8.0.2 to behave as 6.0.8 in that when duplicate elements occurs in JSON payload an exception to be thrown. For example:

var message = "{" +
"\"role\" : \"default\"," +
"\"username\" : \"mallory\"," +
"\"role\" : \"admin\"," +
"\"password\" : \"password!\"" +
"}";
var jobj = JsonConvert.DeserializeObject(message);

Here "role" element occurs twice. In this case 6.0.8 will throw a System.ArgumentException exception, where 8.0.2 deserialize it successfully with admin value for the "role".

@JamesNK My team would really like to be able to detect this case. Would you be amenable to a PR that adds a new JsonSerializerSettings option for switching between the current "accept last" behavior and "emit parse error" behavior?

JsonLoadSettings will have a DuplicatePropertyNameHandling options. Setting it to DuplicatePropertyNameHandling.Error will throw when a duplicate property name is encountered.

How can this functionality be employed by patterns that use JsonConvert.DeserializeObject? If it can't, I'd like to open an issue to add this functionality to JsonSerializerSettings.

I just found this issue too. I thought it was supposed to throw, and it didn't.

How can this functionality be employed by patterns that use JsonConvert.DeserializeObject? If it can't, I'd like to open an issue to add this functionality to JsonSerializerSettings.

see #1922:
с# new JsonLoadSettings { DuplicatePropertyNamesHandling = DuplicatePropertyNamesHandling.Throw }

How can this functionality be employed by patterns that use JsonConvert.DeserializeObject? If it can't, I'd like to open an issue to add this functionality to JsonSerializerSettings.

see #1922:

new JsonLoadSettings { DuplicatePropertyNamesHandling = DuplicatePropertyNamesHandling.Throw }

@mikhail-barg could you elaborate on how one can pass the JsonLoadSettings into JsonConvert.DeserializeObject, which, as I understand, only takes a string and JsonSerializerSettings as arguments?

public static T DeserializeObject<T>(string value, JsonSerializerSettings settings)

Thanks!

+1 for adding this as a property to JsonSerializerSettings.

I'm using Json.NET indirectly through ASP.NET Core, and I was surprised to see it behaving this way.

While we wait for JsonSerializerSettings to get this behavior, I have found this code to work:

public object DeserializeObject(string json, JsonSerializerSettings settings)
{
    JsonSerializer jsonSerializer = JsonSerializer.CreateDefault(settings);
    using (var stringReader = new StringReader(json))
    using (var jsonTextReader = new JsonTextReader(stringReader))
    {
                jsonTextReader.DateParseHandling = DateParseHandling.None;
        JsonLoadSettings loadSettings = new JsonLoadSettings { 
                                                DuplicatePropertyNameHandling = DuplicatePropertyNameHandling.Error 
                                            };
        var jtoken = JToken.ReadFrom(jsonTextReader, loadSettings);
        return jtoken.ToObject<object>(jsonSerializer);
    }
}
Was this page helpful?
0 / 5 - 0 ratings