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
相关产品推荐
相关产品推荐

