.NET Core中API响应error字段多类型反序列化问题
处理System.Text.Json中单值/数组兼容的error字段问题
问题背景
我正在使用.NET原生JSON工具System.Text.Json处理API数据的序列化/反序列化,API响应结构如下:
{ "response-type": { "some-data-field": { "some-data": { ... } }, "some-other-data-field": { "some-other-data": { ... } }, "errors": { "error": { "name": "string", "message": "string" } } } }
对应的模型定义:
public record ResponseModel : ErrorableResponse { public ResponseModelDataField SomeDataField { get; set; } public record ResponseModelDataField { // 内部字段定义 } }
序列化配置及使用代码:
private readonly JsonSerializerOptions serializerOptions = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.KebabCaseLower, Converters = { new JsonStringEnumConverter() }, WriteIndented = true, PropertyNameCaseInsensitive = true, }; var obj = JsonSerializer.Deserialize<ResponseModel>(responseBody, serializerOptions);
核心问题
API返回的error字段既可能是单个包含name和message的对象,也可能是该对象的数组;且API始终返回200状态码,无法提前判断字段类型。不想编写自定义JSON转换器,也不想用try-catch(性能和可读性不佳),需要找到.NET原生的解决方案。
解决方案
方案1:先解析为JsonDocument判断类型,再反序列化
利用JsonDocument先读取响应的结构,判断error字段的类型后,再分别处理成列表,最后赋值给完整模型:
using var doc = JsonDocument.Parse(responseBody); var responseTypeElement = doc.RootElement.GetProperty("response-type"); var errorsElement = responseTypeElement.GetProperty("errors").GetProperty("error"); List<ErrorModel> errors; if (errorsElement.ValueKind == JsonValueKind.Array) { errors = errorsElement.Deserialize<List<ErrorModel>>(serializerOptions); } else { var singleError = errorsElement.Deserialize<ErrorModel>(serializerOptions); errors = new List<ErrorModel> { singleError }; } // 反序列化完整模型并赋值错误列表 var responseModel = responseTypeElement.Deserialize<ResponseModel>(serializerOptions); responseModel.Errors = errors;
方案2:在基类中用动态属性兼容单值/数组
在ErrorableResponse基类中定义一个接收原始数据的object类型属性,再通过计算属性统一转换为列表:
public abstract record ErrorableResponse { // 接收API返回的原始error数据(单值或数组) [JsonPropertyName("error")] public object ErrorRaw { get; set; } // 对外暴露统一的列表格式错误 [JsonIgnore] public List<ErrorModel> Errors { get { return ErrorRaw switch { // 已经是单个ErrorModel对象 ErrorModel single => new List<ErrorModel> { single }, // 是JsonElement数组 JsonElement elem when elem.ValueKind == JsonValueKind.Array => elem.Deserialize<List<ErrorModel>>(serializerOptions), // 是JsonElement单个对象 JsonElement elem when elem.ValueKind == JsonValueKind.Object => new List<ErrorModel> { elem.Deserialize<ErrorModel>(serializerOptions) }, // 其他情况返回空列表 _ => new List<ErrorModel>() }; } } } // 错误模型定义 public record ErrorModel { public string Name { get; set; } public string Message { get; set; } }
这两种方案都无需编写自定义转换器,完全依赖System.Text.Json的原生API,既避免了try-catch的性能损耗,也保证了代码可读性。
内容的提问来源于stack exchange,提问作者jmkmay
相关产品推荐
相关产品推荐

