JSON Error when attempting to consume data from an external API.

Socks93

Active member
Joined
Oct 22, 2021
Messages
29
Programming Experience
Beginner
System.AggregateException
HResult=0x80131500
Message=One or more errors occurred. (Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[OpenAQAirQuality.Models.City]' 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 'meta', line 1, position 8.)
Source=System.Private.CoreLib
StackTrace:
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
at OpenAQAirQuality.ClientConnectionHandler.ClientConnectionHandler.GetCityData() in C:\Users\Aaron\source\repos\OpenAQAirQuality\OpenAQAirQuality\Services\ClientConnectionHandler.cs:line 29
at OpenAQAirQuality.Controllers.airQualityController.getCity() in C:\Users\Aaron\source\repos\OpenAQAirQuality\OpenAQAirQuality\Controllers\airQualityController.cs:line 19
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()

This exception was originally thrown at this call stack:
[External Code]

Inner Exception 1:
JsonSerializationException: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[OpenAQAirQuality.Models.City]' 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 'meta', line 1, position 8.



ClientConnectionHandler code

C#:
        public ActionResult GetCityData()
        {
            IEnumerable<City> city = null;
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("https://docs.openaq.org/");
                var responseTask = client.GetAsync("v2/cities");
                responseTask.Wait();

                var result = responseTask.Result;
                if (result.IsSuccessStatusCode)
                {
                  
                    var readData = result.Content.ReadAsAsync<IList<City>>();
                    readData.Wait(); // this is where the error is occuring
                    city = readData.Result;

                }
                else
                {
                    city = Enumerable.Empty<City>();
                    ModelStateDictionary modelState = new ModelStateDictionary();
                    modelState.AddModelError(string.Empty, "Server error has occured");
                    

                }
            }
            
            return (ActionResult)city;


Class for City model:

C#:
public class City
    {
        [JsonProperty]
        public string country { get; set; }
        [JsonProperty]
        public string city { get; set; }
        [JsonProperty]
        public int count { get; set; }
        [JsonProperty]
        public int locations { get; set; }
        [JsonProperty]
        public DateTime firstUpdated { get; set; }
        [JsonProperty]
        public DateTime lastUpdated { get; set; }
        [JsonProperty]
        public string[] parameters { get; set; }

    }

Does anyone know why this might be occurring and how it can be fixed? Thankyou
 
Read the error closely:
C#:
Inner Exception 1:
JsonSerializationException: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[OpenAQAirQuality.Models.City]' 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 'meta', line 1, position 8.

If you look at the response from the REST call, it looks something like:
C#:
{
  "meta":{
    "name":"openaq-api",
    "license":"CC BY 4.0d",
    "website":"https://u50g7n0cbj.execute-api.us-east-1.amazonaws.com/",
    "page":1,
    "limit":100,
    "found":3151
  },
  "results":[
    {
      "country":"US",
      "city":"007",
      "count":22605,
      "locations":6,
      "firstUpdated":"2018-08-09T09:00:00+00:00",
      "lastUpdated":"2022-05-09T13:00:00+00:00",
      "parameters":["pm25"]
    },
    {
      "country":"US",
      "city":"019",
:

You need to parse just the results part into an IList<City>, but currently you are passing in more than that to ReadAsAsync().
 
@Skydiver Really appreciate the prompt response. I've tried to figure out how to do that exactly and still haven't had any luck. Would you mind explaining how i would go about extracting just the results and give an example?
 
Your best bet would be to just define an outer class that contains that results list that you are expecting.

The alternative is to just use Newtonsoft's JSON.NET LINQ support to get to just the results list part, but at that point you might as well use JSON.NET all the way instead of using the Microsoft JSON serializer to parse the list.
 
Back
Top Bottom