user1352057
user1352057

Reputation: 3182

JSON Deserialization - handle property that can be a array

Question Background:

I am querying Amazons Product Advertising API and trying to desearlize the JSON response to a C# object.

The Issue:

I have received a deserialization error when the code attempts the conversion. I can't quite work out which part is causing the error though. The following shows the error I'm receiving:

Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type'System.Collections.Generic.List`1[ShoppingComparisonEngine.AWS.AwsCommon.Item]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.

To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.

Path 'Items.Item.ASIN', line 1, position 612.

The code:

The following C# are what the Newtonsoft is attempting to serialize to.

Item.cs:

public class Item
{
    [JsonProperty("asin")]
    public string ASIN { get; set; }
    [JsonProperty("parentasin")]
    public string ParentASIN { get; set; }
    [JsonProperty("detailpageurl")]
    public string DetailPageURL { get; set; }
    [JsonProperty("salesrank")]
    public string SalesRank { get; set; }
    [JsonProperty("smallimage")]
    public SmallImage SmallImage { get; set; }
    [JsonProperty("mediumimage")]
    public MediumImage MediumImage { get; set; }
    [JsonProperty("largeimage")]
    public LargeImage LargeImage { get; set; }
    [JsonProperty("imagesets")]
    public ImageSets ImageSets { get; set; }
    [JsonProperty("itemattributes")]
    public ItemAttributes ItemAttributes { get; set; }
    [JsonProperty("offersummary")]
    public OfferSummary OfferSummary { get; set; }
    [JsonProperty("offers")]
    public Offers Offers { get; set; }
}

Items.cs:

    public class Items
{
    [JsonProperty("totalresults")]
    public string TotalResults { get; set; }
    [JsonProperty("totalpages")]
    public string TotalPages { get; set; }
    [JsonProperty("moresearchresultsurl")]
    public string MoreSearchResultsUrl { get; set; }
    [JsonProperty("item")]
    public List<Item> Item { get; set; }
}

JSON:

I believe this is an issue with the fact I have a singe Item whereas the conversion requires a list of them?

{
"Items": {
    "xmlns": "http://webservices.amazon.com/AWSECommerceService/2011-08-01",
    "Request": {
        "IsValid": "True",
        "ItemSearchRequest": {
            "Availability": "Available",
            "Condition": "New",
            "ItemPage": "6",
            "Keywords": "champagne bucket",
            "ResponseGroup": [
                "Medium",
                "Offers"
            ],
            "SearchIndex": "HomeGarden"
        }
    },
    "TotalResults": "51",
    "TotalPages": "6",
    "MoreSearchResultsUrl": "http://www.amazon.co.uk/gp/redirect.html?linkCode=xm2&SubscriptionId=AKIAIFERUZJXWJ3Y2USA&location=http%3A%2F%2Fwww.amazon.co.uk%2Fgp%2Fsearch%3Fkeywords%3Dchampagne%2Bbucket%26url%3Dsearch-alias%253Doutdoor&tag=compar0c2-21&creative=12734&camp=2025",
    "Item": {
        "ASIN": "B00IYO4HRQ",
        "DetailPageURL": "http://www.amazon.co.uk/Bottle-Holder-Accessories-Garden-Maintenance/dp/B00IYO4HRQ%3FSubscriptionId%3DAKIAIFERUZJXWJ3Y2USA%26tag%3Dcompar0c2-21%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3DB00IYO4HRQ",
        "ItemLinks": {
            "ItemLink": [
                {
                    "Description": "Add To Wishlist",
                    "URL": "http://www.amazon.co.uk/gp/registry/wishlist/add-item.html%3Fasin.0%3DB00IYO4HRQ%26SubscriptionId%3DAKIAIFERUZJXWJ3Y2USA%26tag%3Dcompar0c2-21%26linkCode%3Dxm2%26camp%3D2025%26creative%3D12734%26creativeASIN%3DB00IYO4HRQ"
                },
                {
                    "Description": "Tell A Friend",
                    "URL": "http://www.amazon.co.uk/gp/pdp/taf/B00IYO4HRQ%3FSubscriptionId%3DAKIAIFERUZJXWJ3Y2USA%26tag%3Dcompar0c2-21%26linkCode%3Dxm2%26camp%3D2025%26creative%3D12734%26creativeASIN%3DB00IYO4HRQ"
                },
                {
                    "Description": "All Customer Reviews",
                    "URL": "http://www.amazon.co.uk/review/product/B00IYO4HRQ%3FSubscriptionId%3DAKIAIFERUZJXWJ3Y2USA%26tag%3Dcompar0c2-21%26linkCode%3Dxm2%26camp%3D2025%26creative%3D12734%26creativeASIN%3DB00IYO4HRQ"
                },
                {
                    "Description": "All Offers",
                    "URL": "http://www.amazon.co.uk/gp/offer-listing/B00IYO4HRQ%3FSubscriptionId%3DAKIAIFERUZJXWJ3Y2USA%26tag%3Dcompar0c2-21%26linkCode%3Dxm2%26camp%3D2025%26creative%3D12734%26creativeASIN%3DB00IYO4HRQ"
                }
            ]
        },
        "SmallImage": {
            "URL": "http://ecx.images-amazon.com/images/I/31cr9r7XChL._SL75_.jpg",
            "Height": {
                "Units": "pixels",
                "value": "75"
            },
            "Width": {
                "Units": "pixels",
                "value": "75"
            }
        },
        "MediumImage": {
            "URL": "http://ecx.images-amazon.com/images/I/31cr9r7XChL._SL160_.jpg",
            "Height": {
                "Units": "pixels",
                "value": "160"
            },
            "Width": {
                "Units": "pixels",
                "value": "160"
            }
        },
        "LargeImage": {
            "URL": "http://ecx.images-amazon.com/images/I/31cr9r7XChL.jpg",
            "Height": {
                "Units": "pixels",
                "value": "300"
            },
            "Width": {
                "Units": "pixels",
                "value": "300"
            }
        },
        "ImageSets": {
            "ImageSet": [
                {
                    "Category": "swatch",
                    "SwatchImage": {
                        "URL": "http://ecx.images-amazon.com/images/I/31lBLzzkQlL._SL30_.jpg",
                        "Height": {
                            "Units": "pixels",
                            "value": "30"
                        },
                        "Width": {
                            "Units": "pixels",
                            "value": "30"
                        }
                    },
                    "SmallImage": {
                        "URL": "http://ecx.images-amazon.com/images/I/31lBLzzkQlL._SL75_.jpg",
                        "Height": {
                            "Units": "pixels",
                            "value": "75"
                        },
                        "Width": {
                            "Units": "pixels",
                            "value": "75"
                        }
                    },
                    "ThumbnailImage": {
                        "URL": "http://ecx.images-amazon.com/images/I/31lBLzzkQlL._SL75_.jpg",
                        "Height": {
                            "Units": "pixels",
                            "value": "75"
                        },
                        "Width": {
                            "Units": "pixels",
                            "value": "75"
                        }
                    },
                    "TinyImage": {
                        "URL": "http://ecx.images-amazon.com/images/I/31lBLzzkQlL._SL110_.jpg",
                        "Height": {
                            "Units": "pixels",
                            "value": "110"
                        },
                        "Width": {
                            "Units": "pixels",
                            "value": "110"
                        }
                    },
                    "MediumImage": {
                        "URL": "http://ecx.images-amazon.com/images/I/31lBLzzkQlL._SL160_.jpg",
                        "Height": {
                            "Units": "pixels",
                            "value": "160"
                        },
                        "Width": {
                            "Units": "pixels",
                            "value": "160"
                        }
                    },
                    "LargeImage": {
                        "URL": "http://ecx.images-amazon.com/images/I/31lBLzzkQlL.jpg",
                        "Height": {
                            "Units": "pixels",
                            "value": "300"
                        },
                        "Width": {
                            "Units": "pixels",
                            "value": "300"
                        }
                    }
                },
                {
                    "Category": "primary",
                    "SwatchImage": {
                        "URL": "http://ecx.images-amazon.com/images/I/31cr9r7XChL._SL30_.jpg",
                        "Height": {
                            "Units": "pixels",
                            "value": "30"
                        },
                        "Width": {
                            "Units": "pixels",
                            "value": "30"
                        }
                    },
                    "SmallImage": {
                        "URL": "http://ecx.images-amazon.com/images/I/31cr9r7XChL._SL75_.jpg",
                        "Height": {
                            "Units": "pixels",
                            "value": "75"
                        },
                        "Width": {
                            "Units": "pixels",
                            "value": "75"
                        }
                    },
                    "ThumbnailImage": {
                        "URL": "http://ecx.images-amazon.com/images/I/31cr9r7XChL._SL75_.jpg",
                        "Height": {
                            "Units": "pixels",
                            "value": "75"
                        },
                        "Width": {
                            "Units": "pixels",
                            "value": "75"
                        }
                    },
                    "TinyImage": {
                        "URL": "http://ecx.images-amazon.com/images/I/31cr9r7XChL._SL110_.jpg",
                        "Height": {
                            "Units": "pixels",
                            "value": "110"
                        },
                        "Width": {
                            "Units": "pixels",
                            "value": "110"
                        }
                    },
                    "MediumImage": {
                        "URL": "http://ecx.images-amazon.com/images/I/31cr9r7XChL._SL160_.jpg",
                        "Height": {
                            "Units": "pixels",
                            "value": "160"
                        },
                        "Width": {
                            "Units": "pixels",
                            "value": "160"
                        }
                    },
                    "LargeImage": {
                        "URL": "http://ecx.images-amazon.com/images/I/31cr9r7XChL.jpg",
                        "Height": {
                            "Units": "pixels",
                            "value": "300"
                        },
                        "Width": {
                            "Units": "pixels",
                            "value": "300"
                        }
                    }
                }
            ]
        },
        "ItemAttributes": {
            "Brand": "Garden at Home",
            "EAN": "5971458914919",
            "EANList": {
                "EANListElement": "5971458914919"
            },
            "Feature": "Wine Bottle Holder and Cooler Bag Wine Accessories",
            "Label": "Outdoor&Lawn",
            "Manufacturer": "Outdoor&Lawn",
            "MPN": "GG_89773368",
            "PartNumber": "GG_89773368",
            "ProductGroup": "Lawn & Patio",
            "ProductTypeName": "OUTDOOR_LIVING",
            "Publisher": "Outdoor&Lawn",
            "Studio": "Outdoor&Lawn",
            "Title": "Wine Bottle Holder and Cooler Bag Wine Accessories, Garden, Lawn, Maintenance"
        },
        "OfferSummary": {
            "LowestNewPrice": {
                "Amount": "5220",
                "CurrencyCode": "GBP",
                "FormattedPrice": "£52.20"
            },
            "TotalNew": "1",
            "TotalUsed": "0",
            "TotalCollectible": "0",
            "TotalRefurbished": "0"
        },
        "Offers": {
            "TotalOffers": "1",
            "TotalOfferPages": "1",
            "MoreOffersUrl": "http://www.amazon.co.uk/gp/offer-listing/B00IYO4HRQ%3FSubscriptionId%3DAKIAIFERUZJXWJ3Y2USA%26tag%3Dcompar0c2-21%26linkCode%3Dxm2%26camp%3D2025%26creative%3D12734%26creativeASIN%3DB00IYO4HRQ",
            "Offer": {
                "OfferAttributes": {
                    "Condition": "New"
                },
                "OfferListing": {
                    "OfferListingId": "kif7varXuUaD7y55JfdjU7h3YCJvQokyXfgDIWvxOx6%2FqiMbxoPBsyFWCmgo8pbOqZNcezFUCBSdlx3JtRpEpe4Tu7VGv9zncLOYVmoSOUEDNQf1rrKJzZVCjnVPRCKyes0GSlEzlx%2Faht4%2FtjijlvCo14Z3CCcm",
                    "Price": {
                        "Amount": "5800",
                        "CurrencyCode": "GBP",
                        "FormattedPrice": "£58.00"
                    },
                    "SalePrice": {
                        "Amount": "5220",
                        "CurrencyCode": "GBP",
                        "FormattedPrice": "£52.20"
                    },
                    "AmountSaved": {
                        "Amount": "580",
                        "CurrencyCode": "GBP",
                        "FormattedPrice": "£5.80"
                    },
                    "PercentageSaved": "10",
                    "Availability": "Usually dispatched within 1-2 business days",
                    "AvailabilityAttributes": {
                        "AvailabilityType": "now",
                        "MinimumHours": "24",
                        "MaximumHours": "48"
                    },
                    "IsEligibleForSuperSaverShipping": "0",
                    "IsEligibleForPrime": "0"
                }
            }
        },
        "EditorialReviews": {
            "EditorialReview": {
                "Source": "Product Description",
                "Content": "Ice Bucket Bag and Wine Cooler This unique Ice Bucket Bag is attractive and very durable. It is ideal for transporting wine to a friend, hostess or party and arriving with it perfectly chilled.Transparent and waterproof, this wine or Champagne bag also makes a super, space-saving ice bucket that simply folds away after use. It is especially ideal for a picnic or BBQ as it can fold for easy transport and is unbreakableIn addition, this bag makes a great party favor - comes with pocket for place card, business card or gift card. Heavy duty plastic measures 4\" x 4\" x 10\" when open, gift card slot measures 2\" x 3\".",
                "IsLinkSuppressed": "0"
            }
        }
    }
}

EDIT:

This is the code I used to create a Converter to handle both a singular Item object and a List of them.

   public class ItemConverter:JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartArray)
        {
            List<Item> items =  serializer.Deserialize<List<Item>>(reader);

            return items;
        }
        else
        {
            Item itemList = serializer.Deserialize<Item>(reader);
            return new List<Item>(new[] { itemList });
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Upvotes: 1

Views: 993

Answers (2)

toddmo
toddmo

Reputation: 22466

.Net Fiddle: https://dotnetfiddle.net/9MACjN

You had multiple issues:

  • You are actually missing the closing } in your json.

  • You need to deserialize into a parent class (e.g., Response) that contains Items.

  • The Items.Item property needs to be of type Item, not List<Item>, as David said.

  • JsonProperty attributes are not needed at all.

Then it works.

Upvotes: 2

DavidG
DavidG

Reputation: 119166

The Item property in the JSON is a plain object, not a list of objects. If it was supposed to be a list, then the JSON would be enclosed in square brackets to indicate it is an array, e.g.:

"Item": [{ item1 }, { item2}, ... ]

So you need to change your model to match. For example:

public class Items
{
    //snip
    public Item Item { get; set; }
}

Upvotes: 2

Related Questions