简体   繁体   中英

Deserializing a nested .json object in c#

I am trying to deserialize a nested.json ( https://ergast.com/api/f1/current/results.json ) in C# from an API, but I'm kind of stuck. I have looked everywhere for a solution to my problem and haven't found anything helpful yet, I probably just don't grasp how it could help me, considering I am new to c# and APIs in general, and not exactly the most experienced of programmers.

I am calling the following method in an aspx Page_Load where I download the raw.json, format it slightly and deserialize it into racesCollection.

private static RacesCollection GetRacesFromAPI(WebClient webClient)
        {
            String JSON = webClient.DownloadString("https://ergast.com/api/f1/current.json?callback=myParser&limit=1000");
            JObject data = FormatJSON(ref JSON);
            RacesCollection racesCollection = JsonConvert.DeserializeObject<RacesCollection>(data["MRData"]["RaceTable"].ToString());
            return racesCollection;
        }

..This is the collection of races

    public class RacesCollection
    {
        private List<Races> races;
        public List<Races> Races { get => races; set => races = value; }
    }

..and these are the classes i'm trying to deserialize to.

    public class Races
    {
        int season;
        string round;
        string url;
        string raceName;
        string date;
        string time;

        public int Season { get => season; set => season = value; }
        public string Round { get => round; set => round = value; }
        public string Url { get => url; set => url = value; }
        public string RaceName { get => raceName; set => raceName = value; }
        public string Date { get => date; set => date = value; }
        public string Time { get => time; set => time = value; }

        public Dictionary<string, Circuit> Circuit { get; set; }
        public List<Results> Results { get; set; }
    }
    public class Circuit
    {
        string circuitID;
        string circuitUrl;
        string circuitName;

        public string CircuitID { get => circuitID; set => circuitID = value; }
        public string CircuitUrl { get => circuitUrl; set => circuitUrl = value; }
        public string CircuitName { get => circuitName; set => circuitName = value; }
        public Dictionary<string, Location> Location { get; set; }
    }
    public class Results
    {
        int number;
        int position;
        int points;
        int grid;
        int laps;
        string status;
        public int Number { get => number; set => number = value; }
        public int Position { get => position; set => position = value; }
        public int Points { get => points; set => points = value; }
        public int Grid { get => grid; set => grid = value; }
        public int Laps { get => laps; set => laps = value; }
        public string Status { get => status; set => status = value; }
        public Dictionary<string, Driver> Driver { get; set; }
        public Dictionary<string, Constructor> Constructor { get; set; }
    }
    public class Driver
    {
        string driverId;
        public string DriverId { get => driverId; set => driverId = value; }
    }
    public class Constructor
    {
        string constructorId;
        public string ConstructorId { get => constructorId; set => constructorId = value; }
    }


    public class Location
    {
        float lat;
        float @long;
        string locality;
        string country;

        public float Lat { get => lat; set => lat = value; }
        public float Long { get => @long; set => @long = value; }
        public string Locality { get => locality; set => locality = value; }
        public string Country { get => country; set => country = value; }
    }

When running, everything deserializes fine until it reaches Circuit, which throws this exception.

Newtonsoft.Json.JsonSerializationException: 'Error converting value "albert_park" to type 'JSONAPI.Circuit'. Path 'Races[0].Circuit.circuitId', line 10, position 34.'

Inner exception ArgumentException: Could not cast or convert from System.String to JSONAPI.Circuit.

Any help I could get on this would be very appreciated.

JSON libraries will automatically convert the Key-Value pairs to class references for you. Just change public Dictionary<string, Circuit> Circuit { get; set; } public Dictionary<string, Circuit> Circuit { get; set; } public Dictionary<string, Circuit> Circuit { get; set; } to public Circuit Circuit { get; set; } public Circuit Circuit { get; set; } public Circuit Circuit { get; set; } .

This applies to Location , Driver , and Constructor dictionaries in your C# objects.

In the json that you mentioned, circuit is an object in races collection as opposed to dictionary. 在此处输入图像描述 So, please modify Circuit property on your Races class:

public class Races
{
    int season;
    string round;
    string url;
    string raceName;
    string date;
    string time;

    public int Season { get => season; set => season = value; }
    public string Round { get => round; set => round = value; }
    public string Url { get => url; set => url = value; }
    public string RaceName { get => raceName; set => raceName = value; }
    public string Date { get => date; set => date = value; }
    public string Time { get => time; set => time = value; }

    public Circuit Circuit { get; set; }
    public List<Results> Results { get; set; }
}

Also, in the json that posted, Location property's lat and long are strings as opposed to decimals. So, you might need to modify the data types of lat and long as well.

Side but related note, instead of having private properties with lower case, remove private properties and rename public properties to match your json response. If you don't want to rename properties to camel case then either you can decorate each property with JsonProperty (as shown below for the property Season, but same applies for other properties to match json)

public class Races
{
/*  
    int season;
    string round;
    string url;
    string raceName;
    string date;
    string time;
*/
    [JsonProperty("season")]
    public int Season { get; set; }
    /*
    // or use camelcasing like below then no need use JsonProperty attribute
    public int season { get; set; }
    */
    public string Round { get; set; }
    public string Url { get; set; }
    public string RaceName { get; set; }
    public string Date { get; set; }
    public string Time { get; set; }

    public Circuit Circuit { get; set; }
    public List<Results> Results { get; set; }
}

Or you can use CamelCasePropertyNamesContractResolver:

var settings = new JsonSerializerSettings
{
    ContractResolver = new CamelCasePropertyNamesContractResolver()
};
RacesCollection racesCollection = JsonConvert.DeserializeObject<RacesCollection>(data["MRData"]["RaceTable"].ToString(), settings);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM