Bautistf
Bautistf

Reputation: 13

JSON Parsing and Error in C#

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

Answers (2)

Kyle B
Kyle B

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

https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Serialization_DefaultContractResolver.htm#!

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

Greg
Greg

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.

  1. You have spaces for your property name, which are often translated into underscores.
  2. You have a period in your property name, this also may interfere with the dot notation.

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

Related Questions