Jackson Ming Hu Jackson Ming Hu - 4 months ago 26
JSON Question

C# issue - trying to parse JSON but got "Cannot create and populate list type"?

Recently I decided to write a Yahoo Weather PCL library for parsing those APIs (see here for the whole project: https://github.com/huming2207/YahooWeather.NET).

For the coding environment, I'm using Xamarin 6.0.1 with Mono 4.4.1 on Mac OSX 10.11.5, and Visual Studio update 3 on Windows 10 10586.

I've done most of the works and it works, except one thing.

The Yahoo Weather API query result should be something like this:

"item": {
"title": "Conditions for Nome, AK, US at 02:00 PM AKDT",
"lat": "64.499474",
"long": "-165.405792",
"link": "http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-2460286/",
"pubDate": "Sat, 09 Jul 2016 02:00 PM AKDT",
"condition": {
"code": "26",
"date": "Sat, 09 Jul 2016 02:00 PM AKDT",
"temp": "55",
"text": "Cloudy"
},
"forecast": [
{
"code": "28",
"date": "09 Jul 2016",
"day": "Sat",
"high": "55",
"low": "50",
"text": "Mostly Cloudy"
},
{
"code": "39",
"date": "10 Jul 2016",
"day": "Sun",
"high": "56",
"low": "47",
"text": "Scattered Showers"
},
{
"code": "30",
"date": "11 Jul 2016",
"day": "Mon",
"high": "53",
"low": "48",
"text": "Partly Cloudy"
},
{
"code": "32",
"date": "12 Jul 2016",
"day": "Tue",
"high": "59",
"low": "47",
"text": "Sunny"
},
{
"code": "30",
"date": "13 Jul 2016",
"day": "Wed",
"high": "58",
"low": "50",
"text": "Partly Cloudy"
},
{
"code": "28",
"date": "14 Jul 2016",
"day": "Thu",
"high": "53",
"low": "51",
"text": "Mostly Cloudy"
},
{
"code": "30",
"date": "15 Jul 2016",
"day": "Fri",
"high": "56",
"low": "51",
"text": "Partly Cloudy"
},
{
"code": "26",
"date": "16 Jul 2016",
"day": "Sat",
"high": "53",
"low": "52",
"text": "Cloudy"
},
{
"code": "30",
"date": "17 Jul 2016",
"day": "Sun",
"high": "62",
"low": "52",
"text": "Partly Cloudy"
},
{
"code": "30",
"date": "18 Jul 2016",
"day": "Mon",
"high": "56",
"low": "47",
"text": "Partly Cloudy"
}
],
"description": "<![CDATA[<img src=\"http://l.yimg.com/a/i/us/we/52/26.gif\"/>\n<BR />\n<b>Current Conditions:</b>\n<BR />Cloudy\n<BR />\n<BR />\n<b>Forecast:</b>\n<BR /> Sat - Mostly Cloudy. High: 55Low: 50\n<BR /> Sun - Scattered Showers. High: 56Low: 47\n<BR /> Mon - Partly Cloudy. High: 53Low: 48\n<BR /> Tue - Sunny. High: 59Low: 47\n<BR /> Wed - Partly Cloudy. High: 58Low: 50\n<BR />\n<BR />\n<a href=\"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-2460286/\">Full Forecast at Yahoo! Weather</a>\n<BR />\n<BR />\n(provided by <a href=\"http://www.weather.com\" >The Weather Channel</a>)\n<BR />\n]]>",
"guid": {
"isPermaLink": "false"
}
}


So I wrote a "Forecast" and a "Item" JsonObject class to declare for Json.NET library to parse the Json content, which looks like this:

Here is the "Item" class:

namespace YahooWeatherParser
{
[JsonObject()]
public class Item
{
[JsonProperty(PropertyName = "title")]
public string Title { get; set; }

[JsonProperty(PropertyName = "lat")]
public double Latitude { get; set; }

[JsonProperty(PropertyName = "lon")]
public double Longitude { get; set; }

[JsonProperty(PropertyName = "link")]
public string Link { get; set; }

[JsonProperty(PropertyName = "pubDate")]
public string PublishDate { get; set; }

[JsonProperty(PropertyName = "condition")]
public Condition Condition { get; set; }

[JsonProperty(PropertyName = "forecast")]
public Forecast Forecast { get; set; }

[JsonProperty(PropertyName = "description")]
public string Description { get; set; }

[JsonProperty(PropertyName = "guid")]
public Guid Guid { get; set; }
}
}


...and here is the "Forecast" class:

using System;
using Newtonsoft.Json;

namespace YahooWeatherParser
{
[JsonArray]
public class Forecast
{
[JsonProperty(PropertyName = "code")]
public int Code { get; set; }

[JsonProperty(PropertyName = "date")]
public string Date { get; set; }

[JsonProperty(PropertyName = "day")]
public string Day { get; set;}

[JsonProperty(PropertyName = "high")]
public int High { get; set; }

[JsonProperty(PropertyName = "low")]
public int Low { get; set; }

[JsonProperty(PropertyName = "text")]
public string Text { get; set; }

}
}


Then I ran my code, I've got an exception like this:


System.AggregateException: One or more errors occurred. ---> Newtonsoft.Json.JsonSerializationException: Cannot create and populate list type YahooWeatherParser.Forecast. Path 'query.results.channel.item.forecast', line 1, position 1282.


So I Googled around for solutions. I tried if I replace these content below (in "Item" class):

[JsonProperty(PropertyName = "forecast")]
public Forecast Forecast { get; set; }


to:

[JsonProperty(PropertyName = "forecast")]
public List<Forecast> Forecast { get; set; }


It returned me another different exception:


System.AggregateException: One or more errors occurred. --->
Newtonsoft.Json.JsonSerializationException: Cannot deserialize the
current JSON object (e.g. {"name":"value"}) into type
'YahooWeatherParser.Forecast' 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) 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
'query.results.channel.item.forecast[0].code', line 1, position 1290.


So...what should I do next to deal with this problem? Great thanks for your help!

Regards,
Jackson.

Answer

I try it using a clean project and actual newtonsoft json from nuget, your problem is in this line :

using System;
using Newtonsoft.Json;

namespace YahooWeatherParser
{
    [JsonObject]               // <= not [JsonArray] !!! 
    public class Forecast
    {
        [JsonProperty(PropertyName = "code")]
        public int Code { get; set; }

        [JsonProperty(PropertyName = "date")]
        public string Date { get; set; }

        [JsonProperty(PropertyName = "day")]
        public string Day { get; set;}

        [JsonProperty(PropertyName = "high")]
        public int High { get; set; }

        [JsonProperty(PropertyName = "low")]
        public int Low { get; set; }

        [JsonProperty(PropertyName = "text")]
        public string Text { get; set; }

    }
}
Comments