使用Newtonsoft反序列化足球API JSON数据遇阻求助
复杂JSON反序列化问题解决思路及修复方案
问题背景
调用足球数据API获取数据时,无法使用Newtonsoft正确反序列化返回的JSON,目标是提取每个联赛的ID、名称和Logo。
返回的JSON结构
{ "paging": {"current":1,"total":1}, "response": [ { "league":{ "id":4, "name":"Euro Championship", "type":"Cup", "logo":"https://media-2.api-sports.io/football/leagues/4.png" }, "country":{"name":"World","code":null,"flag":null}, "seasons":[ {"year":2008,"start":"2008-06-07","end":"2008-06-29","current":false,"coverage":{"fixtures":{"events":true,"lineups":true,"statistics_fixtures":false,"statistics_players":false},"standings":false,"players":true,"top_scorers":true,"top_assists":true,"top_cards":true,"injuries":false,"predictions":true,"odds":false}}, {"year":2012,"start":"2012-06-08","end":"2012-07-01","current":false,"coverage":{"fixtures":{"events":true,"lineups":true,"statistics_fixtures":false,"statistics_players":false},"standings":false,"players":true,"top_scorers":true,"top_assists":true,"top_cards":true,"injuries":false,"predictions":true,"odds":false}}, {"year":2016,"start":"2016-06-10","end":"2016-07-10","current":false,"coverage":{"fixtures":{"events":true,"lineups":true,"statistics_fixtures":true,"statistics_players":true},"standings":true,"players":true,"top_scorers":true,"top_assists":true,"top_cards":true,"injuries":false,"predictions":true,"odds":false}}, {"year":2020,"start":"2019-03-21","end":"2021-07-11","current":true,"coverage":{"fixtures":{"events":true,"lineups":true,"statistics_fixtures":true,"statistics_players":true},"standings":true,"players":true,"top_scorers":true,"top_assists":true,"top_cards":true,"injuries":false,"predictions":true,"odds":false}} ] } ] }
已定义的C#类
public class FootballCountryModel { [JsonProperty("id")] public int ID { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("logo")] public string Logo { get; set; } } public class Results { [JsonProperty("league")] public Dictionary<string, FootballCountryModel> JsonResults { get; set; } } public class JsonRootObject { [JsonProperty("response")] public Results Rslt { get; set; } } public class LeaguesDeserializedModel { [JsonProperty("parameters")] public object Parameters { get; set; } [JsonProperty("errors")] public object Errors { get; set; } [JsonProperty("results")] public int Results { get; set; } [JsonProperty("paging")] public object Pagin { get; set; } [JsonProperty("response")] public List<FootballCountryModel> Response { get; set; } }
当前反序列化代码
dynamic jsonObj = JsonConvert.DeserializeObject<Results>(response.Content);
反序列化失败原因
- 层级不匹配:JSON的
response是数组,每个元素包含league对象,但定义的Results类将league映射为Dictionary<string, FootballCountryModel>,完全不符合结构;且直接用Results反序列化,未匹配JSON的根层级。 - 类型错误:
LeaguesDeserializedModel中的Response直接定义为List<FootballCountryModel>,跳过了JSON中response元素里的league嵌套层级,导致无法正确映射。
解决思路与修复方案
1. 修正类结构(严格匹配JSON层级)
只保留需要的字段,忽略无关内容:
// 对应JSON中的league对象,复用原有字段定义 public class FootballLeagueModel { [JsonProperty("id")] public int ID { get; set; } [JsonProperty("name")] public string Name { get; set; } [JsonProperty("logo")] public string Logo { get; set; } } // 对应response数组中的单个元素,仅保留需要的league字段 public class LeagueResponseItem { [JsonProperty("league")] public FootballLeagueModel League { get; set; } } // 对应JSON根对象,包含paging和response数组 public class LeagueRootModel { [JsonProperty("paging")] public PagingModel Paging { get; set; } [JsonProperty("response")] public List<LeagueResponseItem> Response { get; set; } } // 可选:如果需要paging数据,定义对应类,否则可改为object类型 public class PagingModel { [JsonProperty("current")] public int Current { get; set; } [JsonProperty("total")] public int Total { get; set; } }
2. 正确的反序列化代码
// 反序列化为根对象类型 var root = JsonConvert.DeserializeObject<LeagueRootModel>(response.Content); // 提取所有联赛信息 var leagues = root.Response.Select(item => item.League).ToList(); // 示例:遍历输出联赛数据 foreach (var league in leagues) { Console.WriteLine($"ID: {league.ID}, Name: {league.Name}, Logo: {league.Logo}"); }
核心思路总结
- 层级严格匹配:类的嵌套结构必须和JSON的键值层级完全对应,不能跳过中间节点;
- 类型精准对应:JSON数组对应
List<T>,单个对象对应具体类,避免错误使用Dictionary或其他不匹配类型; - 按需定义字段:不需要的字段可以不定义,Newtonsoft会自动忽略,减少类的复杂度;
- 显式字段映射:用
JsonProperty确保C#属性名和JSON键名一致,避免因命名规范差异导致映射失败。
内容的提问来源于stack exchange,提问作者LyuboWorking
相关产品推荐
相关产品推荐

