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

Mat*_*ach 0 c# json.net

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

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

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

这很容易反序列化为假设TList<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;
}
Run Code Online (Sandbox Code Playgroud)

我可以使用此方法然后直接反序列化为正确的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;
Run Code Online (Sandbox Code Playgroud)

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

fer*_*ero 9

你至少可以代替JObject.Parse()JToken.Parse(),因为JToken是两个基类JObjectJArray.然后你可以检查结果是a JArray还是a JObject(或者可能是JValue整数).

var result = JToken.Parse(response);

if (result is JArray)
{
    // ...
}
else if (result is JObject)
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

还要看一下JToken文档.