You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 21:06:07