1

I'm attempting to deserialize a response from a REST API using JSON.NET.

dynamic resultObject = JsonConvert.DeserializeObject(responseText);

I'd like to not have to define classes for the different kinds of responses the REST API returns, as it changes often. I'd like to take advantage of dynamic runtime variables.

In VS2015, I've added watchers to see the values directly after the line of code above executes.

resultObject resolves to a null object, however, the watcher shows that the line code run directly results in aNewtonsoft.Json.Linq.JObject which is populated with the deserialized response string.

Why doesn't the dynamic var resultObject populate with the 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);
                }

            }

UPDATE:

Contents of the JSON to parse:

JSON updated to remove debug information - problem persists.

https://jsonblob.com/57cb00c7e4b0dc55a4f2abe9

UPDATE 2:

It appears that JsonConvert.DeserializeObject() is parsing my JSON to have extra brackets around the entire object.

String as it is generated from the response stream:

"{\"message\":\"422 Unprocessable Entity\",\"errors\":[[\"The email must be a valid email address.\"],[\"The password must be at least 8 characters.\"]],\"status_code\":422}"

value of 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 }}

UPDATE 3: Converting to JObject.Parse resulted in the same output.

I changed the variable from type dynamic to JObject - to accept the response from JObject.Parse() and still the variable is set to null.

3
  • What's the text of response? With simple json object I get properties in dynamic object just fine. Commented Sep 3, 2016 at 16:52
  • @Evk I've added the contents to the question. There is quite a bit of unnecessary debug info in the request. I'll remove that and see if that works. Commented Sep 3, 2016 at 17:00
  • 1
    @dbc Updated to remove screenshot and provide minimal, complete code sample. Commented Sep 3, 2016 at 23:17

2 Answers 2

1

I think, JSonConvert is invalid for solve your task. You can simply use JObject and JObject.Parse and then iterate "errors" property by Item

Sign up to request clarification or add additional context in comments.

3 Comments

Migrating from JsonConvert.DeserializeObject() to JObject.Parse() concluded in the exact same result. The response from JObject.Parse has an extra set of braces around the object.
Even when I declare the object to be of type JObject it still doesn't take the assignment. Very weird!
Initializing the object to an empty JObject, then running JObject.Parse() worked - I don't think that's how it's supposed to work but it does.
0

Your problem is that, in the following line, you are assuming that "errors" is an array of JSON objects, each with a property named "Val":

foreach (var error in responseObject["errors"].Children())
{
     errors.Add(error.Val);
}

However, "errors" is actually an array of arrays, and so error.Val evaluates to null. Instead you need to do something like:

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);
    }
}

Personally, however, I recommend avoiding use of dynamic because you lose the advantages of static, compile-time type checking. Code full of dynamic objects can also be hard to debug. Instead I would recommend the use of LINQ to JSON, specifically the SelectTokens() along with the JSONPath recursive descent operator ..* to pick out all string values inside the "errors" object like so:

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.

Example fiddle.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.