使用Refit解析包含对象与空数组的怪异API响应问题
解决JSON数组到C#对象的解析问题
问题原因
你的API响应最外层是数组类型([{}, []]),但你定义的TableDetailResponse是键值对对象类型,两者结构不匹配,导致解析失败。序列化器无法自动将数组映射到包含Table和Errors两个属性的对象上。
解决方案
这里提供三种可行的处理方式:
方式一:直接解析为数组后手动转换
修改Refit接口的返回类型为object[],调用后手动解析数组元素:
public interface SOJOSurveyService { [Get("/survey/{id}")] Task<object[]> QueryQuestionsByFlow([AliasAs("id")] string questionID); }
调用示例:
var responseArray = await service.QueryQuestionsByFlow("your-id"); // 解析第一个元素为QuestionTable var questionTable = JsonConvert.DeserializeObject<QuestionTable>(responseArray[0].ToString()); // 第二个元素是空数组,直接转为List<object> var errors = JsonConvert.DeserializeObject<List<object>>(responseArray[1].ToString());
方式二:使用ValueTuple匹配数组结构
利用C# ValueTuple直接匹配JSON数组的两个元素,序列化器会自动映射:
public interface SOJOSurveyService { [Get("/survey/{id}")] Task<(QuestionTable Table, List<object> Errors)> QueryQuestionsByFlow([AliasAs("id")] string questionID); }
调用示例:
var (table, errors) = await service.QueryQuestionsByFlow("your-id"); // 直接使用table和errors即可
方式三:自定义JSON转换器(推荐)
创建自定义转换器,将数组结构映射到你原有的TableDetailResponse对象,这样可以保留原有的类结构:
- 实现自定义转换器:
public class TableDetailResponseConverter : JsonConverter<TableDetailResponse> { public override TableDetailResponse ReadJson(JsonReader reader, Type objectType, TableDetailResponse existingValue, bool hasExistingValue, JsonSerializer serializer) { var jsonArray = JArray.Load(reader); return new TableDetailResponse { Table = jsonArray[0].ToObject<QuestionTable>(serializer), Errors = jsonArray[1].ToObject<List<object>>(serializer) }; } public override void WriteJson(JsonWriter writer, TableDetailResponse value, JsonSerializer serializer) { var jsonArray = new JArray(); jsonArray.Add(JToken.FromObject(value.Table, serializer)); jsonArray.Add(JToken.FromObject(value.Errors, serializer)); jsonArray.WriteTo(writer); } }
- 在
TableDetailResponse类上标记转换器:
[JsonConverter(typeof(TableDetailResponseConverter))] public class TableDetailResponse { public QuestionTable Table { get; set; } public List<object> Errors { get; set; } }
- 保持原Refit接口不变即可正常解析:
public interface SOJOSurveyService { [Get("/survey/{id}")] Task<TableDetailResponse> QueryQuestionsByFlow([AliasAs("id")] string questionID); }
内容的提问来源于stack exchange,提问作者manaclan
相关产品推荐
相关产品推荐

