C#解析API返回的特殊JSON响应内容
看起来你遇到的是JSON数组到C#强类型对象的映射问题——这个API返回的产品数据是扁平数组形式,而你定义的是带命名属性的类,默认的JSON序列化工具(不管是Newtonsoft.Json还是System.Text.Json)都没法直接自动映射,不过有两种可靠的解决办法,我帮你梳理一下:
首先先明确你的输入和目标:
API返回的JSON结构(简化版)
{ "response": { "results": [ [ 1002, "Brent's Test Product o Fun", "TEST001", "1234567-", "100000000281", "12345678", "", "", true, "Brightpearl", "2020-06-18T13:38:01.000-05:00", "2021-04-27T07:45:24.000-05:00", 439, null, 74, 1, "LIVE", null ], [ 1003, "Brent's Test Product 2", "TEST002", "", "", "", "", "", true, "Brightpearl", "2020-08-31T00:53:26.000-05:00", "2021-04-27T07:45:24.000-05:00", 439, null, 74, 1, "LIVE", null ] ] } }
你定义的目标类(需要先调整可空属性)
因为JSON里有null值(比如productGroupId和primarySupplierId字段),所以要把对应的属性改成可空类型,避免转换时抛出异常:
public class SkuSearchResults { public int productId { get; set; } public string productName { get; set; } public string SKU { get; set; } public string barcode { get; set; } public string EAN { get; set; } public string UPC { get; set; } public string ISBN { get; set; } public string MPN { get; set; } public bool stockTracked { get; set; } public string salesChannelName { get; set; } public string createdOn { get; set; } public string updatedOn { get; set; } public int brightpearlCategoryCode { get; set; } public int? productGroupId { get; set; } // 改为可空int public int brandId { get; set; } public int productTypeId { get; set; } public string productStatus { get; set; } public int? primarySupplierId { get; set; } // 改为可空int }
解决方案1:手动遍历映射(简单直接)
这种方法适合快速实现,不需要额外配置序列化规则,直接解析JSON数组后逐个赋值:
使用Newtonsoft.Json的示例代码
using Newtonsoft.Json.Linq; using System.Collections.Generic; // 假设jsonString是API返回的完整JSON字符串 var jsonObj = JObject.Parse(jsonString); var resultsArray = jsonObj["response"]["results"].ToObject<JArray>(); var skuList = new List<SkuSearchResults>(); foreach (var item in resultsArray) { var productData = item.ToObject<JArray>(); var sku = new SkuSearchResults { // 严格按照JSON数组的索引对应类属性 productId = (int)productData[0], productName = (string)productData[1], SKU = (string)productData[2], barcode = (string)productData[3], EAN = (string)productData[4], UPC = (string)productData[5], ISBN = (string)productData[6], MPN = (string)productData[7], stockTracked = (bool)productData[8], salesChannelName = (string)productData[9], createdOn = (string)productData[10], updatedOn = (string)productData[11], brightpearlCategoryCode = (int)productData[12], // 处理null值 productGroupId = productData[13].Type == JTokenType.Null ? null : (int?)productData[13], brandId = (int)productData[14], productTypeId = (int)productData[15], productStatus = (string)productData[16], primarySupplierId = productData[17].Type == JTokenType.Null ? null : (int?)productData[17] }; skuList.Add(sku); }
解决方案2:自定义JSON转换器(优雅复用)
如果需要多次处理这类API响应,或者希望代码更优雅,可以自定义一个JSON转换器,让序列化工具自动完成映射:
使用System.Text.Json的自定义转换器示例
using System.Text.Json; using System.Text.Json.Serialization; using System.Collections.Generic; // 自定义转换器 public class SkuSearchResultsConverter : JsonConverter<SkuSearchResults> { public override SkuSearchResults Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType != JsonTokenType.StartArray) { throw new JsonException("Expected JSON array for product data"); } var sku = new SkuSearchResults(); int index = 0; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndArray) break; switch (index) { case 0: sku.productId = reader.GetInt32(); break; case 1: sku.productName = reader.GetString(); break; case 2: sku.SKU = reader.GetString(); break; case 3: sku.barcode = reader.GetString(); break; case 4: sku.EAN = reader.GetString(); break; case 5: sku.UPC = reader.GetString(); break; case 6: sku.ISBN = reader.GetString(); break; case 7: sku.MPN = reader.GetString(); break; case 8: sku.stockTracked = reader.GetBoolean(); break; case 9: sku.salesChannelName = reader.GetString(); break; case 10: sku.createdOn = reader.GetString(); break; case 11: sku.updatedOn = reader.GetString(); break; case 12: sku.brightpearlCategoryCode = reader.GetInt32(); break; case 13: sku.productGroupId = reader.TokenType == JsonTokenType.Null ? null : reader.GetInt32(); break; case 14: sku.brandId = reader.GetInt32(); break; case 15: sku.productTypeId = reader.GetInt32(); break; case 16: sku.productStatus = reader.GetString(); break; case 17: sku.primarySupplierId = reader.TokenType == JsonTokenType.Null ? null : reader.GetInt32(); break; default: // 跳过响应末尾的额外元数据 reader.Skip(); break; } index++; } return sku; } public override void Write(Utf8JsonWriter writer, SkuSearchResults value, JsonSerializerOptions options) { // 如果不需要把对象序列回数组,可以留空或抛出异常 throw new NotImplementedException("Serialization from SkuSearchResults to array is not implemented"); } } // 定义外层响应类 public class ApiResponse { public List<SkuSearchResults> results { get; set; } // 如果有其他元数据字段,在这里添加对应属性 } // 使用转换器进行反序列化 var serializerOptions = new JsonSerializerOptions(); serializerOptions.Converters.Add(new SkuSearchResultsConverter()); var apiResponse = JsonSerializer.Deserialize<ApiResponse>(jsonString, serializerOptions); var skuList = apiResponse.results;
关键注意事项
- 索引对应关系:一定要严格核对JSON数组的索引和类属性的对应顺序,一旦API返回的数组顺序变化,代码会出错,建议和API文档确认字段顺序是否固定。
- 类型转换:注意JSON中的数据类型和C#属性的匹配,比如日期字符串直接存为
string,如果需要转成DateTime,可以在映射时用DateTime.Parse()或DateTime.TryParse()处理。 - 空值处理:对于JSON中的
null值,必须用可空类型(int?)接收,否则会抛出转换异常。
内容的提问来源于stack exchange,提问作者Brent Allison
相关产品推荐
相关产品推荐

