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

Web API中FromBody绑定模型时单/多Order场景兼容问题

当然可以搞定!这种对接上游系统时遇到的格式兼容问题太常见了,.NET Web API完全支持让你的模型同时兼容单个Order对象和Order数组两种JSON格式,下面给你两种实用的解决方案:

解决方案1:自定义JSON转换器(推荐)

这是最优雅也最通用的方式,通过自定义JSON序列化/反序列化逻辑,让框架自动识别并转换单个对象或数组。下面以.NET Core/.NET 5+默认使用的System.Text.Json为例:

步骤1:创建自定义转换器类

这个转换器会判断传入的JSON是单个对象还是数组,然后统一转为List<Order>:

public class SingleOrArrayConverter<T> : JsonConverter<List<T>>
{
    public override List<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // 检查当前JSON token类型
        if (reader.TokenType == JsonTokenType.StartObject)
        {
            // 单个对象:反序列化为T后包装成List
            var singleItem = JsonSerializer.Deserialize<T>(ref reader, options);
            return new List<T> { singleItem };
        }
        else if (reader.TokenType == JsonTokenType.StartArray)
        {
            // 数组:直接反序列化为List<T>
            return JsonSerializer.Deserialize<List<T>>(ref reader, options);
        }

        throw new JsonException("JSON格式不符合要求,预期是单个对象或数组");
    }

    public override void Write(Utf8JsonWriter writer, List<T> value, JsonSerializerOptions options)
    {
        // 序列化时可选逻辑:如果List只有一个元素,输出单个对象而非数组
        if (value?.Count == 1)
        {
            JsonSerializer.Serialize(writer, value[0], options);
        }
        else
        {
            JsonSerializer.Serialize(writer, value, options);
        }
    }
}

步骤2:在模型上应用转换器

修改你的ProductModel,给Order字段加上转换器特性:

public class ProductModel
{
    [Required]
    public int ProductId { get; set; }

    [JsonConverter(typeof(SingleOrArrayConverter<Order>))]
    public List<Order> Order { get; set; }
}

public class Order
{
    public int OrderId { get; set; }
    public string Name { get; set; }
}

这样不管上游传入的是单个Order对象:

{
  "productId": 1,
  "order": {
    "orderId": 100,
    "name": "Test Order"
  }
}

还是Order数组:

{
  "productId": 1,
  "order": [
    {
      "orderId": 100,
      "name": "Test Order"
    },
    {
      "orderId": 101,
      "name": "Another Order"
    }
  ]
}

你的ProductModel.Order都能正确获取到对应的List<Order>集合。

解决方案2:利用模型内部属性转换(备选)

如果你不想写自定义转换器,也可以通过模型内部的私有属性来分别接收单个对象和数组,再对外暴露统一的List<Order>属性:

public class ProductModel
{
    [Required]
    public int ProductId { get; set; }

    // 用于接收单个Order对象
    [JsonPropertyName("order")]
    private Order SingleOrder { get; set; }

    // 用于接收Order数组
    [JsonPropertyName("order")]
    private List<Order> MultipleOrders { get; set; }

    // 对外提供的统一属性
    public List<Order> Order
    {
        get
        {
            if (MultipleOrders != null)
                return MultipleOrders;
            if (SingleOrder != null)
                return new List<Order> { SingleOrder };
            return null;
        }
        set
        {
            if (value?.Count == 1)
                SingleOrder = value[0];
            else
                MultipleOrders = value;
        }
    }
}

这种方式不需要额外的转换器,但模型结构会稍微复杂一点,适合简单场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:30:16