将UPS API RatingResponse反序列化为C#强类型对象的问题
解决UPS REST API RatedPackage反序列化问题的几种方案
针对UPS API返回的RatedPackage可能是单个对象或数组的情况,以下是几种直接可行的处理方式:
方案一:使用Json.NET自定义转换器(推荐)
如果项目使用Newtonsoft.Json(Json.NET),可以编写通用转换器自动将单个对象转为数组:
public class SingleOrArrayConverter<T> : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(List<T>) || objectType == typeof(T[]); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var token = JToken.Load(reader); if (token.Type == JTokenType.Array) { return token.ToObject(objectType, serializer); } // 单个对象时包装成数组/列表 var list = Activator.CreateInstance(objectType) as IList; var item = token.ToObject<T>(serializer); list.Add(item); return list; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { serializer.Serialize(writer, value); } }
接着在RatingResponse模型的RatedPackage属性上标记转换器:
public class RatingResponse { // 其他属性... [JsonConverter(typeof(SingleOrArrayConverter<RatedPackage>))] public RatedPackage[] RatedPackages { get; set; } }
这样无论API返回单个对象还是数组,都能正确反序列化为数组类型。
方案二:使用System.Text.Json自定义转换器(.NET Core/.NET 5+)
如果使用内置的System.Text.Json,可编写对应转换器:
public class SingleOrArrayConverter<T> : JsonConverter<T[]> { public override T[] Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { var item = JsonSerializer.Deserialize<T>(ref reader, options); return new[] { item }; } else if (reader.TokenType == JsonTokenType.StartArray) { return JsonSerializer.Deserialize<T[]>(ref reader, options); } throw new JsonException("Expected object or array"); } public override void Write(Utf8JsonWriter writer, T[] value, JsonSerializerOptions options) { JsonSerializer.Serialize(writer, value, options); } }
然后在模型属性上配置:
public class RatingResponse { // 其他属性... [JsonConverter(typeof(SingleOrArrayConverter<RatedPackage>))] public RatedPackage[] RatedPackages { get; set; } }
方案三:先反序列化为动态类型再转换
若不想编写转换器,可先将响应反序列化为动态类型,手动判断RatedPackage类型后转换:
Json.NET版本:
var responseJson = await httpResponse.Content.ReadAsStringAsync(); var jObject = JObject.Parse(responseJson); var ratedPackageToken = jObject["RatedShipment"]["RatedPackage"]; RatedPackage[] ratedPackages; if (ratedPackageToken.Type == JTokenType.Array) { ratedPackages = ratedPackageToken.ToObject<RatedPackage[]>(); } else { ratedPackages = new[] { ratedPackageToken.ToObject<RatedPackage>() }; } // 映射其他属性到RatingResponse var ratingResponse = jObject.ToObject<RatingResponse>(); ratingResponse.RatedPackages = ratedPackages;
System.Text.Json版本:
var responseJson = await httpResponse.Content.ReadAsStringAsync(); using var doc = JsonDocument.Parse(responseJson); var root = doc.RootElement; var ratedPackageElement = root.GetProperty("RatedShipment").GetProperty("RatedPackage"); RatedPackage[] ratedPackages; if (ratedPackageElement.ValueKind == JsonValueKind.Array) { ratedPackages = JsonSerializer.Deserialize<RatedPackage[]>(ratedPackageElement); } else { var singlePackage = JsonSerializer.Deserialize<RatedPackage>(ratedPackageElement); ratedPackages = new[] { singlePackage }; } // 映射到RatingResponse var ratingResponse = JsonSerializer.Deserialize<RatingResponse>(responseJson); ratingResponse.RatedPackages = ratedPackages;
这种方式适合临时处理,但通用性不如自定义转换器。
内容的提问来源于stack exchange,提问作者JClarkCDS
相关产品推荐
相关产品推荐

