我尝试使用JSON.NET从REST API反序列化响应。
dynamic resultObject = JsonConvert.DeserializeObject(responseText);
我不想为REST API返回的不同类型的响应定义类,因为它经常更改。我想利用dynamic
运行时变量。
在VS2015中,我已经添加了观察者,以便在上面的代码行执行后直接查看值。
resultObject
解析为空object
,然而,观察者显示直接运行的行代码会导致Newtonsoft.Json.Linq.JObject
填充反序列化的响应字符串。
为什么动态变量resultObject
不会填充JObject
?
var responseStream = e.Response?.GetResponseStream();
string responseText = "";
if (responseStream != null)
{
using (var reader = new StreamReader(responseStream))
{
responseText = reader.ReadToEnd();
}
dynamic responseObject = JsonConvert.DeserializeObject(responseText);
foreach (var error in responseObject["errors"].Children())
{
errors.Add(error.Val);
}
}
更新
要解析的JSON的内容:
更新了JSON以删除调试信息 - 问题仍然存在。
https://jsonblob.com/57cb00c7e4b0dc55a4f2abe9
更新2:
似乎JsonConvert.DeserializeObject()
正在解析我的JSON,在整个对象周围有额外的括号。
从响应流生成的字符串:
"{\"message\":\"422 Unprocessable Entity\",\"errors\":[[\"The email must be a valid email address.\"],[\"The password must be at least 8 characters.\"]],\"status_code\":422}"
JsonConvert.DeserializeObject()的值:
{{
"message": "422 Unprocessable Entity",
"errors": [
[
"The email must be a valid email address."
],
[
"The password must be at least 8 characters."
]
],
"status_code": 422
}}
更新3:
转换为JObject.Parse
会产生相同的输出。
我将变量从dynamic
类型更改为JObject
- 以接受来自JObject.Parse()
的响应,并且该变量仍设置为null。
答案 0 :(得分:1)
我认为,JSonConvert对于解决您的任务无效。您只需使用JObject和JObject.Parse,然后重复错误"财产由Item
答案 1 :(得分:0)
您的问题在于,在以下行中,您假设"errors"
是一个JSON 对象的数组,每个都有一个名为"Val"
的属性:
foreach (var error in responseObject["errors"].Children())
{
errors.Add(error.Val);
}
但是,"errors"
实际上是数组的数组,因此error.Val
的计算结果为null
。相反,你需要做类似的事情:
var errors = new List<string>();
dynamic responseObject = JsonConvert.DeserializeObject(responseText);
foreach (dynamic errorList in responseObject["errors"].Children())
{
foreach (dynamic error in errorList.Children())
{
errors.Add((string)error);
}
}
但是,我个人建议避免使用dynamic
因为你失去了静态编译时类型检查的优点。充满dynamic
个对象的代码也很难调试。相反,我建议使用LINQ to JSON,特别是SelectTokens()
以及JSONPath递归下降运算符..*
来挑选"errors"
对象中的所有字符串值像这样:
var token = JToken.Parse(responseText);
var errors = token.SelectTokens("errors..*") // Iterate through all descendants of the "errors" property
.OfType<JValue>() // Filter those that are primitive values
.Select(v => (string)v) // Convert to their string values
.ToList(); // And evaluate the query as a list.
示例fiddle。