I am getting intermittent error 'Newtonsoft.Json.Linq.JValue' does not contain a definition for 'Contains'

Viewed 55

I am getting intermittent error when executing my .NET C# code. Below is the error.

  Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'Newtonsoft.Json.Linq.JValue' does not contain a definition for 'value'

Below is the code I am using -

dynamic obj = JsonConvert.DeserializeObject(response);

string value = obj.responseObject.value.token;

I am getting this error when I try to execute the above code -

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'Newtonsoft.Json.Linq.JValue' does not contain a definition for 'value'

Please, any help is appreciated. Thank you.

1 Answers

Your problem is that you are attempting to deserialize JSON that usually looks like the following:

{"responseObject" : { "value" : { "token" : "some token" } } }

By using Json.NET's dynamic runtime binding to JSON properties:

dynamic obj = JsonConvert.DeserializeObject(response);
string value = obj.responseObject.value.token;

In cases where your code works, the JSON contains the properties you expect with the types you expect. But when your JSON fails to confirm to your expected schema -- specifically the value of "value" is an atomic JSON value or null rather than a nested object -- then Newtonsoft's dynamic binding code will fail with the error you see. E.g. given the following two JSON samples:

{"responseObject" : { "value" : "some atomic value such as an error message" } }
{"responseObject" : { "value" : null } }

then obj.responseObject.value.token will throw a 'Newtonsoft.Json.Linq.JValue' does not contain a definition for 'token' exception.

Demo fiddle #1 here.

So, what are your options for a workaround?

dynamic binding has a convenient syntax which can look enticing, however when you use dynamic you lose all compile-time error checking, and often find yourself with completely inscrutable errors when your objects are not exactly as you expect. Since Json.NET's dynamic deserialization actually deserializes to a LINQ-to-JSON JToken hierarchy, you should do so explicitly:

var obj = JsonConvert.DeserializeObject<JObject>(response);

And now to access obj.responseObject.value.token in a fault-tolerant manner, your options include:

  1. Use SelectToken():

    var value = (string)obj.SelectToken("responseObject.value.token");
    

    SelectToken() is more fault-tolerant than dynamic binding and will simply return null if no token exists at the specified path.

  2. Use the JTtoken indexer and explicitly check that obj["responseObject"]?["value"] is a JSON object:

    var value = (string)(obj["responseObject"]?["value"] as JObject)?["token"];
    
  3. As a variation of #2, you could introduce some extension methods as follows:

    public static partial class JsonExtensions
    {
        public static JObject AsJObject(this JToken @in) => @in.As<JObject>();
        public static TJToken As<TJToken>(this JToken @in) where TJToken : JToken => @in as TJToken;
    }
    

    and do:

    var value = (string)obj["responseObject"].AsJObject()?["value"].AsJObject()?["token"];
    
  4. You could use Json.NET Schema to validate your JSON before parsing. Note however that Json.NET Schema is not free.

Demo fiddle #2 demonstrating options 1-3 here.

Related