我正在使用Json.Net库(适用于.Net v3.5)来处理来自EBoss CRM API的响应的取消序列化。据我所见,API文档是相当不稳定的,所以我不得不亲自探究它,看看能得到什么样的响应。
我想要一个单独的包装器类EBossApiResponse<T>
,它将为API发送回的任何错误消息提供属性,再加上一个包含T
类型的取消序列化数据的属性(它将被限制为一个抽象基类,它充当我创建的任何类的底层类型,以对返回的数据进行建模)。
我最初的试探揭示了第一个问题。有效的请求可以返回一组对象,例如:https://ebosscrm.com/api.php/job_type.json
这将很容易分解为List<EBossJobType>
的假设T
。请注意,结果中没有error属性。
但是,对同一个端点的格式错误的请求会返回不同的结果: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),或者取消序列化到左侧的List<EBossEntityType>
,创建一个新的EBossApiResponse<List<EBossEntityType>>
,并设置其.Data
属性。
然后我意识到o.SelectToken("message")
不起作用,因为o
将是一个数组,而不是一个对象。.SelectToken()
是否可以采用"[0].message"
形式的模式来获取第一个项目的消息属性?
这个怎么样?
JObject o = JObject.Parse(response);
JArray arr = o as JArray;
return (arr != null && (JObject)arr[0].SelectToken("message") != null)
|| o.SelectToken("error") != null;
还是我完全搞错了,而这整件事有一个更优雅的解决方案?
您至少可以用JToken.Parse()
替换JObject.Parse()
,因为JToken
是JObject
和JArray
的基类。然后,您可以检查结果是JArray
还是JObject
(或者可能是像整数一样的JValue
)。
var result = JToken.Parse(response);
if (result is JArray)
{
// ...
}
else if (result is JObject)
{
// ...
}
还可以查看JToken的文档。