Reputation: 13
I am having trouble parsing a JSON from the Alpha Vantage API. The output of the JSON is as follows
{
"Realtime Currency Exchange Rate": {
"1. From_Currency Code": "BTC",
"2. From_Currency Name": "Bitcoin",
"3. To_Currency Code": "CNY",
"4. To_Currency Name": "Chinese Yuan",
"5. Exchange Rate": "43211.50782620",
"6. Last Refreshed": "2018-04-11 17:48:12",
"7. Time Zone": "UTC"
}
}
I am parsing it like this
using (var wc = new System.Net.WebClient())
json = wc.DownloadString(link);
dynamic stuff = JsonConvert.DeserializeObject(json);
string test = stuff["Realtime Currency Exchange Rate"]["5. Exchange Rate"];
However when I run the code, I am getting this error
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'Cannot perform runtime binding on a null reference'
Anyone have any idea? If I print the value in a textbox, the value shows up but afterwards it shows that error. I am coding in c#
Thanks
Upvotes: 1
Views: 681
Reputation: 2909
Try creating an object to serialize to and use the JsonProperty attribute to map the json properties to the C# properties:
public class RealtimeCurrencyExchangeRate
{
[JsonProperty("1. From_Currency Code")]
public string CurrencyCode { get; set; }
}
Then use the correct type when deserializing.
var obj = JsonConvert.DeserializeObject<RealtimeCurrencyExchangeRate >(json);
References:
Spaces handling: Deserializing JSON when fieldnames contain spaces
DeserializeObject: https://www.newtonsoft.com/json/help/html/DeserializeObject.htm
Or, if you want to dynamically read the properties, you can create a custom contract resolver:
public class AlphaVantageApiContractResolver : DefaultContractResolver
{
protected override string ResolvePropertyName(string propertyName)
{
// derive the C#property name from the JSON property name
var cSharpPropertyName = propertyName;
// Remove all periods from the C#property name
cSharpPropertyName = cSharpPropertyName.Replace(".", "");
// replace all spaces with underscores
cSharpPropertyName = cSharpPropertyName .Replace(" ", "_");
// The value you return should map to the exact C# property name in your class so you need to create classes to map to.
return cSharpPropertyName;
}
}
and use this while deserializing:
var jsonSettings = new JsonSerializerSettings();
jsonSettings.ContractResolver = new AlphaVantageApiContractResolver();
var obj = JsonConvert.DeserializeObject<MyClass>(json, jsonSettings);
You will still have to create classes that map to the objects but now you don't have to worry about the JsonProperty attribute on every property. Just remember to remove periods and replace spaces with underscores in your C# property names. You will also have to write some code to remove numbers at the beginning of property names because this isn't allowed in C#.
If you can't pre-define your classes, you will need to deserialize anonymous objects and work with that.
Upvotes: 1
Reputation: 11478
Your issue more than likely stems from your JSON. Though your JSON is valid, you violate a couple of principals which may be affecting the binder.
You could do the approach recommended by Kyle to bind. If you would like to use dynamic, then you could fix the above, then do the following syntax.
dynamic json = JsonConvert.Deserialize<object>(...);
var value = json.realTimeCurrencyExchangeRate.fromCurrencyCode;
The C# binder doesn't like a period when you utilize dot notation and spaces, when they're translated with underscores. So you could use your space, but the translation may be different. You would need to look closer at your object.
Upvotes: 0