ASP.NET Core中如何反序列化World Bank无属性名的复杂JSON响应
世界银行异构JSON数组响应反序列化解决方案
该API返回的外层是异构JSON数组,两个元素类型完全不同,无法直接映射为单一类型的集合,可通过以下步骤处理:
1 先修正现有实体类的问题
原有实体存在两处不匹配问题,需调整:
WorldBankApiResponse.Value定义为int会丢失小数精度,改为decimal?可适配空值/小数场景- 补充
WorldBankApiResponseGlobal的Lastupdated属性 - 新增JSON属性映射特性,适配接口返回的蛇形/小驼峰命名
修正后代码:
using System.Text.Json.Serialization; public class WorldBankApiResponseGlobal { [JsonPropertyName("page")] public int Page { get; set; } [JsonPropertyName("pages")] public int Pages { get; set; } [JsonPropertyName("per_page")] public int Per_Page { get; set; } [JsonPropertyName("total")] public int Total { get; set; } [JsonPropertyName("sourceid")] public string Sourceid { get; set; } [JsonPropertyName("sourcename")] public string Sourcename { get; set; } [JsonPropertyName("lastupdated")] public string Lastupdated { get; set; } } public class WorldBankApiIdValue { [JsonPropertyName("id")] public string Id { get; set; } [JsonPropertyName("value")] public string Value { get; set; } } public class WorldBankApiResponse { [JsonPropertyName("indicator")] public WorldBankApiIdValue Indicator { get; set; } [JsonPropertyName("country")] public WorldBankApiIdValue Country { get; set; } [JsonPropertyName("value")] public decimal? Value { get; set; } [JsonPropertyName("date")] public string Date { get; set; } [JsonPropertyName("countryiso3code")] public string Countryiso3code { get; set; } }
2 最简方案:拆分JSON数组分别反序列化
使用.NET默认的System.Text.Json解析外层数组,按索引分别映射到对应类型,代码示例:
// 注入IHttpClientFactory后创建客户端 var client = _httpClientFactory.CreateClient(); const string requestUrl = "https://api.worldbank.org/v2/country/can/indicator/NY.GDP.PCAP.KD.ZG?format=json&mrv=2"; var response = await client.GetAsync(requestUrl); response.EnsureSuccessStatusCode(); // 解析外层为JSON数组 var jsonContent = await response.Content.ReadAsStringAsync(); var jsonArray = System.Text.Json.Nodes.JsonNode.Parse(jsonContent)?.AsArray(); // 校验响应格式合法性 if (jsonArray == null || jsonArray.Count < 2) { throw new InvalidOperationException("接口返回格式不符合预期"); } // 分别反序列化分页元数据和指标数据 var pageMetadata = jsonArray[0].Deserialize<WorldBankApiResponseGlobal>(); var indicatorList = jsonArray[1].Deserialize<List<WorldBankApiResponse>>();
3 进阶方案:自定义转换器实现直接映射
如果需要复用该逻辑,可自定义JsonConverter,直接将响应反序列化为统一包装类,无需每次手动拆分:
3.1 定义统一返回包装类
public class WorldBankFullResponse { public WorldBankApiResponseGlobal PageMetadata { get; set; } public List<WorldBankApiResponse> IndicatorData { get; set; } }
3.2 实现自定义转换器
public class WorldBankResponseConverter : JsonConverter<WorldBankFullResponse> { public override WorldBankFullResponse? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType != JsonTokenType.StartArray) { throw new JsonException(); } var result = new WorldBankFullResponse(); // 读取第一个元素:分页元数据 reader.Read(); result.PageMetadata = JsonSerializer.Deserialize<WorldBankApiResponseGlobal>(ref reader, options); // 读取第二个元素:指标数组 reader.Read(); result.IndicatorData = JsonSerializer.Deserialize<List<WorldBankApiResponse>>(ref reader, options); // 读取数组结束标记 reader.Read(); return result; } public override void Write(Utf8JsonWriter writer, WorldBankFullResponse value, JsonSerializerOptions options) { throw new NotImplementedException(); } }
3.3 直接使用GetFromJsonAsync反序列化
var serializerOptions = new JsonSerializerOptions(); serializerOptions.Converters.Add(new WorldBankResponseConverter()); var fullResult = await client.GetFromJsonAsync<WorldBankFullResponse>(requestUrl, serializerOptions);
如果使用Newtonsoft.Json
逻辑完全一致,仅解析类改为JArray即可:
var jArray = Newtonsoft.Json.Linq.JArray.Parse(jsonContent); var pageMetadata = jArray[0].ToObject<WorldBankApiResponseGlobal>(); var indicatorList = jArray[1].ToObject<List<WorldBankApiResponse>>();
内容的提问来源于stack exchange,提问作者Nicolas Dontigny
相关产品推荐
相关产品推荐

