lukeguy
lukeguy

Reputation: 118

JSON.NET Conflicting property name when using JsonPropertyAttribute

I have a following JSON string:

{
    "items" : "1",
    "itemdetails": 
    [
        {
            "id" : "5",
            "name:" "something"
        }
    ]
}

items represents item count and actual items are in itemdetails.

I would like to deserialize this to a class like this:

class Parent
{
    JsonProperty("itemdetails")]
    public IEnumerable<Item> Items { get; set; }
}

class Item
{
    [JsonProperty("id")]
    public long Id { get; set; }

    [JsonProperty("name")]
    public string Name {get; set; }
}

However, when I call

JsonConvert.DeserializeObject<Parent>(inputString)

I get a JsonSerializationException that string "1" cannot be converted to IEnumerable<Item>. I guess the parser is trying to deserialize items from JSON into Items property because they match by name. And it's ignoring the JsonProperty attribute.

Is this by design? Any workarounds? Thanks!

EDIT

As Brian Rogers commented, this code as it is works correctly. I figured that I missed to add a piece of the puzzle.

The problem is if I want to use private collection setters and initialize those properties from the constructor.

public Parent(IEnumerable<Item> items)
{
    this.Items = items;
}

This is causing the exception to be thrown. What should I do here? Annotate constructor arguments somehow? Or use ConstructorHandling.AllowNonPublicDefaultConstructor?

Upvotes: 1

Views: 5114

Answers (1)

Brian Rogers
Brian Rogers

Reputation: 129827

I see two issues. First, your JsonProperty attribute is malformed.

You have:

JsonProperty("itemdetails"]

It should be:

[JsonProperty("itemdetails")]

Secondly, part of your JSON is invalid.

You have this:

 "name:" "something",

It should be:

 "name" : "something"

After fixing both of those problems, it worked just fine for me. Here is the test program I used:

class Program
{
    static void Main(string[] args)
    {
        string json = @"
        {
            ""items"" : ""1"",
            ""itemdetails"": 
            [
                {
                    ""id"" : ""5"",
                    ""name"" : ""something""
                }
            ]
        }";

        Parent parent = JsonConvert.DeserializeObject<Parent>(json);
        foreach (Item item in parent.Items)
        {
            Console.WriteLine(item.Name + " (" + item.Id + ")");
        }
    }
}

class Parent
{
    [JsonProperty("itemdetails")]
    public IEnumerable<Item> Items { get; set; }
}

class Item
{
    [JsonProperty("id")]
    public long Id { get; set; }

    [JsonProperty("name")]
    public string Name { get; set; }
}

Output:

something (5)

EDIT

OK, so if I understand you correctly, your real Parent class actually looks like this:

class Parent
{
    public Parent(IEnumerable<Item> items)
    {
        this.Items = items;
    }

    [JsonProperty("itemdetails")]
    public IEnumerable<Item> Items { get; private set; }
}

In this case you have a couple of choices to get it to work:

You either can change the name of the parameter in your constructor to match the JSON, e.g.:

    public Parent(IEnumerable<Item> itemdetails)
    {
        this.Items = itemdetails;
    }

OR you can add a separate private constructor for Json.Net to use:

class Parent
{
    public Parent(IEnumerable<Item> items)
    {
        this.Items = items;
    }

    [JsonConstructor]
    private Parent()
    {
    }

    [JsonProperty("itemdetails")]
    public IEnumerable<Item> Items { get; private set; }
}

Upvotes: 3

Related Questions