简体   繁体   中英

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

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.

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. Eg 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 loose 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. UseSelectToken() :

     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 is not free.

Demo fiddle #2 demonstrating options 1-3 here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM