System.Text.Json.JsonException: 'The JSON value could not be converted to System.Collections.Generic.List`1

126 Views Asked by At

I am attempting to build a WPF Application to store Holiday Details in a SQL Server database. I request an address from end user and attempt to GeoCode the address. To do this I make a web request from code and attempt to deserialise the Json response that I get back. The HTTP call is successful and returns the expected formatted Json response but the deserialisation to my classes fails. WebRequest from code

s = WebRequest.CreateHttp("https://maps.googleapis.com/maps/api/geocode/json" & postdata)

Attempt to deserialise the Json response received as below:-

{
    "results": [
        {
            "address_components": [
                {
                    "long_name": "6",
                    "short_name": "6",
                    "types": [
                        "street_number"
                    ]
                },
                {
                    "long_name": "Clitheroe Road",
                    "short_name": "Clitheroe Rd",
                    "types": [
                        "route"
                    ]
                },
                {
                    "long_name": "Lytham St Annes",
                    "short_name": "Lytham St Annes",
                    "types": [
                        "locality",
                        "political"
                    ]
                },
                {
                    "long_name": "Lytham Saint Annes",
                    "short_name": "Lytham Saint Annes",
                    "types": [
                        "postal_town"
                    ]
                },
                {
                    "long_name": "Lancashire",
                    "short_name": "Lancashire",
                    "types": [
                        "administrative_area_level_2",
                        "political"
                    ]
                },
                {
                    "long_name": "England",
                    "short_name": "England",
                    "types": [
                        "administrative_area_level_1",
                        "political"
                    ]
                },
                {
                    "long_name": "United Kingdom",
                    "short_name": "GB",
                    "types": [
                        "country",
                        "political"
                    ]
                },
                {
                    "long_name": "FY8 3QN",
                    "short_name": "FY8 3QN",
                    "types": [
                        "postal_code"
                    ]
                }
            ],
            "formatted_address": "6 Clitheroe Rd, Lytham St Annes, Lytham Saint Annes FY8 3QN, UK",
            "geometry": {
                "bounds": {
                    "northeast": {
                        "lat": 53.752827,
                        "lng": -3.0009766
                    },
                    "southwest": {
                        "lat": 53.7526356,
                        "lng": -3.0012806
                    }
                },
                "location": {
                    "lat": 53.7527275,
                    "lng": -3.0011181
                },
                "location_type": "ROOFTOP",
                "viewport": {
                    "northeast": {
                        "lat": 53.7540894302915,
                        "lng": -2.999763319708498
                    },
                    "southwest": {
                        "lat": 53.7513914697085,
                        "lng": -3.002461280291502
                    }
                }
            },
            "place_id": "ChIJTyNBERpBe0gRgk37kcNrmdA",
            "types": [
                "premise"
            ]
        }
    ],
    "status": "OK"
}

with the deserialised Classes below:-

// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
public class AddressComponent
{
    public string long_name { get; set; }
    public string short_name { get; set; }
    public List<string> types { get; set; }
}
public class Bounds
{
    public Northeast northeast { get; set; }
    public Southwest southwest { get; set; }
}
public class Geometry
{
    public Bounds bounds { get; set; }
    public Location location { get; set; }
    public string location_type { get; set; }
    public Viewport viewport { get; set; }
}
public class Location
{
    public double lat { get; set; }
    public double lng { get; set; }
}
public class Northeast
{
    public double lat { get; set; }
    public double lng { get; set; }
}
public class Result
{
    public List<AddressComponent> address_components { get; set; }
    public string formatted_address { get; set; }
    public Geometry geometry { get; set; }
    public string place_id { get; set; }
    public List<string> types { get; set; }
}
public class Root
{
    public List<Result> results { get; set; }
    public string status { get; set; }
}
public class Southwest
{
    public double lat { get; set; }
    public double lng { get; set; }
}
public class Viewport
{
    public Northeast northeast { get; set; }
    public Southwest southwest { get; set; }
}

gave the following error:-

 System.Text.Json.JsonException:
  'The JSON value could not be converted to 
 System.Collections.Generic.List`1[Holiday.GetAddress+AddressComponent]. 
 Path: $.results[0].address_components[0] | LineNumber: 6 | BytePositionInLine: 13.'

Hunting around for hints tips and clues revealed that deserialiser is only expecting a single "results" even though Json result shows an array.

2

There are 2 best solutions below

3
Graeme Baillie On

Found a link in stack overflow that suggested I use Edit - Paste Special - Paste Json as Classes in Visual studio to generate my Class Structure. This gave me the following:

Public Class Rootobject
    Public results() As Result
    Public status As String
End Class

Public Class Result
    Public address_components() As Address_Components
    Public formatted_address As String
    Public geometry As Geometry
    Public place_id As String
    Public types() As String
End Class

Public Class Geometry
    Public bounds As Bounds
    Public location As Location
    Public location_type As String
    Public viewport As Viewport
End Class

Public Class Bounds
    Public northeast As Northeast
    Public southwest As Southwest
End Class

Public Class Northeast
    Public lat As Single
    Public lng As Single
End Class

Public Class Southwest
    Public lat As Single
    Public lng As Single
End Class

Public Class Location
    Public lat As Single
    Public lng As Single
End Class

Public Class Viewport
    Public northeast As Northeast1
    Public southwest As Southwest1
End Class

Public Class Northeast1
    Public lat As Single
    Public lng As Single
End Class

Public Class Southwest1
    Public lat As Single
    Public lng As Single
End Class

Public Class Address_Components
    Public long_name As String
    Public short_name As String
    Public types() As String
End Class

results() As Result now given instead of results As List(Of Results) generated by https://json2csharp.com/

Code can now deserialise the json response without any code amendments.

0
Dev On

Try with the following code ,

class Program
    {
        static void Main()
        {
            string json = // your JSON string here;
    
            Root root = JsonConvert.DeserializeObject<Root>(json);
    
           // here you can desterilize the data 
             Console.WriteLine($"Formatted Address: {root.Results[0].FormattedAddress}");
        }
    }