JsonConvert.DeserializeObject 生成空动态对象

JsonConvert.DeserializeObject generates a null dynamic object

我正在尝试使用 JSON.NET 反序列化来自 REST API 的响应。

dynamic resultObject = JsonConvert.DeserializeObject(responseText);

我不想为 REST API returns 的不同类型的响应定义 类,因为它经常变化。我想利用 dynamic 运行 时间变量。

在 VS2015 中,我添加了观察者以在上面的代码行执行后直接查看值。

resultObject 解析为 null 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() 的响应,但变量仍设置为空。

我认为,JSonConvert 无法解决您的任务。您可以简单地使用 JObject and JObject.Parse and then iterate "errors" property by Item

你的问题是,在下一行中,你假设 "errors" 是 JSON objects 的数组,每个对象都有一个 属性 命名为 "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, specifically the SelectTokens() along with the 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.