JsonConvert.DeserializeObject生成一个空的动态对象

时间:2016-09-03 16:32:35

标签: c# json visual-studio json.net dynamic-variables

我尝试使用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。

2 个答案:

答案 0 :(得分:1)

我认为,JSonConvert对于解决您的任务无效。您只需使用JObjectJObject.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