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:
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.
Use the JTtoken
indexer and explicitly check that obj["responseObject"]?["value"]
is a JSON object:
var value = (string)(obj["responseObject"]?["value"] as JObject)?["token"];
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"];
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.