【问题标题】:Deserializing a nested .json object in c#在 C# 中反序列化嵌套的 .json 对象
【发布时间】:2020-05-01 16:50:11
【问题描述】:

我正在尝试从 API 反序列化 C# 中的嵌套 .json (https://ergast.com/api/f1/current/results.json),但我有点卡住了。我到处寻找解决问题的方法,但还没有发现任何有用的东西,我可能只是不明白它对我有什么帮助,考虑到我是 c# 和 API 的新手,而不是最有经验的程序员。

我在下载原始 .json 的 aspx Page_Load 中调用以下方法,稍微格式化并将其反序列化为 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;
        }

..这是种族合集

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

..这些是我试图反序列化的类。

    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; }
    }

运行时,一切都正常反序列化,直到它到达 Circuit,这会引发此异常。

Newtonsoft.Json.JsonSerializationException:“将值“albert_park”转换为类型“JSONAPI.Circuit”时出错。路径 'Races[0].Circuit.circuitId',第 10 行,位置 34。'

内部异常 ArgumentException:无法从 System.String 转换或转换为 JSONAPI.Circuit。

如果我能在这方面得到任何帮助,我们将不胜感激。

【问题讨论】:

  • JSON 键应该区分大小写。您的 C# 对象中有 CircuitID,而 JSON 是 circuitId。更新你的 C# 对象,看看它是如何工作的。
  • 感谢您的建议。不幸的是,它仍然抛出同样的异常。
  • public Dictionary&lt;string, Circuit&gt; Circuit { get; set; } 更改为 public Circuit Circuit { get; set; } 电路是 JSON 对象,而不是字典。与电路上的Location 相同。
  • 谢谢你,肖恩!这行得通。虽然我偶然发现了另一个问题,但我仍然坚持尝试让 Results 工作,因为它是一个数组。使用public Results Results{ get; set; } 不会返回异常,但它只是空值。我尝试过使用public List&lt;Results&gt; Results { get; set; }System.Collections.ObjectModel.Collection&lt;Results&gt; Results{ get; set; },但它们都不起作用,结果始终为空。
  • 没关系,想通了!在我对此感到沮丧的同时,我没有看到我之前粘贴的同一个链接是我尝试使用的同一个链接。无论如何,感谢您的帮助,非常感谢!

标签: c# json api serialization json.net


【解决方案1】:

JSON 库会自动为您将键值对转换为类引用。 只需将public Dictionary&lt;string, Circuit&gt; Circuit { get; set; } 更改为public Circuit Circuit { get; set; }

这适用于 C# 对象中的 LocationDriverConstructor 字典。

【讨论】:

    【解决方案2】:

    在您提到的 json 中,电路是竞赛集合中的一个对象,而不是字典。 因此,请修改 Races 类的 Circuit 属性:

    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; }
    }
    

    此外,在发布的 json 中,Location 属性的 lat 和 long 是字符串,而不是小数。因此,您可能还需要修改 lat 和 long 的数据类型。

    附带但相关的说明,而不是使用小写的私有属性,删除私有属性并重命名公共属性以匹配您的 json 响应。如果您不想将属性重命名为驼峰式,那么您可以使用 JsonProperty 装饰每个属性(如下所示的属性 Season,但同样适用于其他属性以匹配 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; }
    }
    

    或者你可以使用 CamelCasePropertyNamesContractResolver:

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

    【讨论】:

    • 感谢您的意见!我将尝试使用此方法制作另一个变体。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-12
    • 1970-01-01
    • 2014-03-08
    • 1970-01-01
    相关资源
    最近更新 更多