使用Json.Net进行条件数组/对象反序列化

时间:2012-10-30 15:11:10

标签: c# json.net

我正在使用Json.Net库(用于.NET v3.5)来处理来自EBoss CRM API的响应的反序列化。据我所知,API文档相当不稳定,因此我不得不自己动手来看看可以引出什么样的响应。

我希望有一个包装类EBossApiResponse<T>,它将为API发回的任何错误消息提供属性,以及包含T类型的反序列化数据的属性(将限制为一个抽象基类,它充当我为模拟返回数据而创建的任何类的基础类型。)

我最初的戳戳揭示了第一个问题。有效请求可以返回一组对象,例如:https://ebosscrm.com/api.php/job_type.json

这很容易反序列化为假设的T List<EBossJobType>。请注意,结果中没有错误属性。

对同一端点的格式错误的请求会返回不同的内容:https://ebosscrm.com/api.php/job_type.json?search[foo]=1

在这种情况下,返回一个数组,其中包含一个具有名为message的单个属性的对象。

(注意,有些名为search[something]的参数有效,但foo永远不是有效的something

还有可能返回显式错误。在我看来,API正在捕获异常并格式化包含调试信息的JSON响应:https://ebosscrm.com/api.php/candidates.json?uid=114&api_key=f34js3kj

在这种情况下,返回的JSON不是数组,而是单个对象。我不确定如何迎合这些不同的响应结构。我最初的想法是拥有类似的东西:

protected bool IsNonDataResponse(string response)
{
    JObject o = JObject.Parse(response);
    return o.SelectToken("message") != null || o.SelectToken("error") != null;
}

我可以使用此方法然后直接反序列化为正确的EBossApiResponse<T>类型(如果为true,填充错误消息但保留.Data属性== null),或反序列化到右侧{{ 1}},创建一个新的List<EBossEntityType>,并设置其EBossApiResponse<List<EBossEntityType>>属性。

然后我意识到.Data将不起作用,因为o.SelectToken("message")将是一个数组,而不是一个对象。可以o采用.SelectToken()形式的模式来获取第一个项目的消息属性吗?

这个怎么样?

"[0].message"

或者我在完全错误的树上吠叫,对整个事情有一个更优雅的解决方案?

1 个答案:

答案 0 :(得分:9)

您至少可以将JObject.Parse()替换为JToken.Parse(),因为JTokenJObjectJArray的基类。然后,您可以检查结果是JArray还是JObject(或类似整数的JValue)。

var result = JToken.Parse(response);

if (result is JArray)
{
    // ...
}
else if (result is JObject)
{
    // ...
}

还要查看documentation for JToken