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

如何用C# System.Text.Json处理带请求标记的动态API响应

处理基于ItemType和Flags的动态API响应(System.Text.Json)

问题背景

使用C#及System.Text.Json对接第三方API时,SearchItemsRequestSpec.ItemType决定了响应的基础数据格式,SearchItemsRequest.Flags则控制响应中是否包含可选内容段。当前仅能处理固定类型的响应,无法适配这种动态结构变化,需要设计一套灵活的实体类和反序列化逻辑。

解决方案

1. 抽象通用响应结构

先抽离所有响应的公共字段,将Items定义为泛型,适配不同ItemType的实体:

public class SearchItemsResponse<T>
{
    [JsonPropertyName("searchSpec")]
    public SearchItemsResponseSpec SearchSpec { get; set; }

    [JsonPropertyName("dataFlags")]
    public long DataFlags { get; set; }

    [JsonPropertyName("totalItemsCount")]
    public uint TotalItemsCount { get; set; }

    [JsonPropertyName("indexFrom")]
    public uint IndexFrom { get; set; }

    [JsonPropertyName("indexTo")]
    public uint IndexTo { get; set; }

    [JsonPropertyName("items")]
    public List<T> Items { get; set; }
}

// 公共响应规格类(匹配API返回的searchSpec字段)
public class SearchItemsResponseSpec
{
    [JsonPropertyName("itemsType")]
    public SearchItemsItemType ItemsType { get; set; }
    // 可根据API文档补充其他公共字段
}

2. 按ItemType拆分实体类

为每种ItemType创建独立的实体类,将可选内容段定义为可空属性,并通过JsonIgnoreCondition忽略空值序列化:

// Unit类型实体
public class Item_Unit
{
    // BaseFlag对应的基础字段
    [JsonPropertyName("id")]
    public long Id { get; set; }

    [JsonPropertyName("name")]
    public string Name { get; set; }

    // 可选字段:CustomProperties(对应Flags=2)
    [JsonPropertyName("custom_properties")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public UnitCustomProperties? CustomProperties { get; set; }

    // 可选字段:BillingProperties(对应Flags=4)
    [JsonPropertyName("billing")]
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public UnitBillingProperties? BillingProperties { get; set; }

    // 其他可选字段按此模式扩展...

    // 计算属性:解析DataFlags为枚举,方便判断可选字段是否存在
    [JsonIgnore]
    public UnitResponseFlags ActiveFlags { get; set; }
}

// 可选字段对应的嵌套类
public class UnitCustomProperties
{
    [JsonPropertyName("props")]
    public Dictionary<string, string> Props { get; set; }
}

public class UnitBillingProperties
{
    [JsonPropertyName("balance")]
    public decimal Balance { get; set; }
    // 补充API返回的其他账单字段
}

3. 动态反序列化逻辑

根据请求的ItemType,选择对应的实体类型进行反序列化:

public object DeserializeSearchResponse(string json, SearchItemsItemType itemType)
{
    return itemType switch
    {
        SearchItemsItemType.avl_unit => JsonSerializer.Deserialize<SearchItemsResponse<Item_Unit>>(json),
        SearchItemsItemType.avl_group => JsonSerializer.Deserialize<SearchItemsResponse<Item_Group>>(json),
        // 新增ItemType时,添加对应的分支即可
        _ => throw new NotSupportedException($"不支持的ItemType:{itemType}")
    };
}

// 使用示例
var request = new SearchItemsRequest();
request.Spec.ItemsType = SearchItemsItemType.avl_unit;
request.Flags = (long)(UnitResponseFlags.BaseFlag | UnitResponseFlags.CustomProperties);

// 发送请求获取响应字符串
string responseJson = await SendApiRequest(request);

// 反序列化为对应类型
var unitResponse = (SearchItemsResponse<Item_Unit>)DeserializeSearchResponse(responseJson, request.Spec.ItemsType);

// 标记当前激活的Flags,判断可选字段是否存在
foreach (var unit in unitResponse.Items)
{
    unit.ActiveFlags = (UnitResponseFlags)unitResponse.DataFlags;
    if (unit.ActiveFlags.HasFlag(UnitResponseFlags.CustomProperties))
    {
        // 处理自定义属性逻辑
        var customProps = unit.CustomProperties?.Props;
    }
}

4. 扩展与维护注意事项

  • 启用项目的Nullable引用类型(项目文件中添加<Nullable>enable</Nullable>),让可空属性的语义更清晰。
  • 新增ItemType时,只需添加对应的实体类(如Item_Group)和反序列化分支,无需修改核心逻辑。
  • 若API返回的字段格式特殊,可自定义JsonConverter处理复杂类型转换。

内容的提问来源于stack exchange,提问作者Hecatonchires

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 07:14:56