4

Complete Novice to JSON - this is my first foray into JSON with C#.

I have a single record returned from an HTTP get request.

var exchRateData = Get($"https://api.exchangeratesapi.io/2018-10-30?base=EUR&symbols=AUD");

Returns : {"date":"2018-10-30","rates":{"AUD":1.6025},"base":"EUR"}.

The AUD and 1.6025 values are both variables in the GET request. So the GET request can be for SGD or INR in which it returns:

{"date":"2018-10-30","rates":{"SGD":0.0187977737},"base":"INR"}

Always ONE record with levels is returned like those two examples above.

What I would like is to access the values of the second level values,

i.e {"AUD":1.6025} or {"SGD":0.0187977737}

I have tried:

var jsonResult = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(exchRateData);
 foreach (var keyValue in jsonResult)
 {
 try
 {
 LblGetValues.Text = LblGetValues.Text + "Key: " + keyValue.Key + " Value:" + keyValue.Value + "<br>";
 if (keyValue.Key == "date")
 LblDate.Text = keyValue.Value;
//This is where I get stuck.
 if (keyValue.Key == "rates")
 {
// I would like to be able to do this here : 
//string currencyCode = "AUD" (or "SGD" if second GET request)
//double currencyRate = 1.6025 (or 0.0187977737 if second GET request)
 //JArray secondLevel = new JArray("rates");
 // LblRate.Text = keyValue.Value.ToString();
 }
 if (keyValue.Key == "base")
 LblBase.Text = keyValue.Value;
 }
 catch (Exception errMsg)
 {
 LblMsg.Text = errMsg.Message + errMsg.StackTrace;
 }
 }

Please help....

PrathapG
7891 gold badge7 silver badges23 bronze badges
asked Nov 1, 2018 at 8:00
5
  • this might help - it has an answer with a nice extension method: stackoverflow.com/questions/16079116/… Commented Nov 1, 2018 at 8:12
  • A little passive-aggressive there TheGeneral. ePossum, for the record though, a question that's easy to read is easier to answer, here's a link to the markdown for formatting questions you might have in future: stackoverflow.com/editing-help Commented Nov 1, 2018 at 8:21
  • I can't see the "passive-aggressive" you refer to. I feel good this morning and I wont let this little snide spoil from @user3577502 spoil my day. Thanks Mihir Dave for your solution. Works like charm and you have made my day.... Commented Nov 1, 2018 at 9:21
  • @ePossum the accepted solution will work if you request 1 currency only, not multiple (e.g. api.exchangeratesapi.io/…). Check my answer Commented Nov 1, 2018 at 9:43
  • Yes @Rui Jarimba. You are right. However, I did accept this solution because we need only one rate for this project where. We need a conversion between two currency codes. The API also has options for multiple dates, date ranges etc and we did not want any scope creep by looking at solutions beyond returning a single exchange rate, However, your answer is useful because we will be embarking on currency triangulation after we finish the conversion project. The two projects are completely separate so no need to adopt same solution for both. I have marked up your answer of course. Commented Nov 1, 2018 at 10:08

3 Answers 3

2

I would suggest using JSON.NET

Here you will deserialize your JSON string into your c# model class

your model class will look like this Model Generated using json2csharp

public class Rates
{
 [JsonProperty(PropertyName = "fieldName")]
 public double currency { get; set; }
}
public class RootObject
{
 public string date { get; set; }
 public Rates rates { get; set; }
 public string @base { get; set; }
}

Then this is how you deserialize it using JSON.NET

// THis works for normal secanario but it won't work for you 
var exchangeRates = JsonConvert.DeserializeObject<RootObject>("Your Json String goes here");

But then your JSON scenario is bit complex so you have to use CustomContractResolver

Here is Example for that

ContractResolver class

internal class CustomContractResolver : DefaultContractResolver
{
 public CustomContractResolver(string fieldName)
 {
 FieldName = fieldName;
 }
 public string FieldName { get; set; }
 protected override string ResolvePropertyName(string propertyName)
 {
 return propertyName == "fieldName" ? FieldName : base.ResolvePropertyName(propertyName);
 }
}

how to use this setting

var settings = new JsonSerializerSettings
{
 DefaultValueHandling = DefaultValueHandling.Ignore,
 MissingMemberHandling = MissingMemberHandling.Ignore,
 ContractResolver = new CustomContractResolver("Pass Your currency here")
};
// Make Http Calls here and replace returned string in below method
var data = JsonConvert.DeserializeObject<RootObject>("Your JSON String", setting);
// Here You can access your currency rates
double currencyRate = data.currency;
answered Nov 1, 2018 at 8:27

1 Comment

Perfect - I think your solution recognizes the complexity of having a key as a variable and resolves that issue well. I have implemented this successfully without needing the "foreach" loop. The only change I have had to make is replacing base.currency with base.rates.currency and that was quite simple. Many Thanks, Mihir.
1

The accepted solution works fine if there is only one rate (which is what the OP wants), but it won't work with more than 1 rate. Also, it adds extra complexity, which can be avoided by using a Dictionary (see below).

Example - the following request (AUD, USD, GBP)

https://api.exchangeratesapi.io/2018-10-30?base=EUR&symbols=AUD,USD,GBP

Will return the following json:

{"date":"2018-10-30","rates":{"USD":1.1372,"GBP":0.89148,"AUD":1.6025},"base":"EUR"}

You can use the following C# class to deserialize your json string:

public class ExchangeRate
{
 [JsonProperty("date")]
 public string Date { get; set; }
 [JsonProperty("rates")]
 public Dictionary<string, decimal> Rate { get; set; }
 [JsonProperty("base")]
 public string Base { get; set; }
}

Deserializing the json string:

string json = @"{""date"":""2018-10-30"",""rates"":{""USD"":1.1372,""GBP"":0.89148,""AUD"":1.6025},""base"":""EUR""}";
ExchangeRate rate = JsonConvert.DeserializeObject<ExchangeRate>(json);

Result:

Deserialized object

answered Nov 1, 2018 at 9:11

1 Comment

Yes @Rui Jarimba. You are right. However, I did accept the previous solution because we need only one rate for this project where. We need a conversion between two currency codes. However, your answer is useful because we will be embarking on currency triangulation after we finish the conversion project. The two projects are completely separate so no need to adopt same solution for both. I have marked up your answer of course.
0
 public class Rates
 {
 public double AUD { get; set; }
 }
 public class ObjectCurrency
 {
 public string date { get; set; }
 public Rates rates { get; set; }
 public string @base { get; set; }
 }
 var data= JsonConvert.DeserializeObject<ObjectCurrency>(exchRateData);
answered Nov 1, 2018 at 8:18

5 Comments

Perfect! The "trick" is to call JsonConvert.DeserializeObject<T>() with the correct "type", as you've shown here. I'm not sure if this code will necessarily work for the OP as-is - he might need to change a few things. But it's definitely the correct approach.
I have indicated in my notes above:
what happens when request changes from AUD to INR? this code will break.
I have indicated in my notes above: that AUD and SGD are variables in the Get request. It could be MXP or even some other variable. In effect, I have a key which is a variable in the JSON statement. AUD could be any 3 digit currency code. The class Rates could contain SGD, MXP etc?
Correct @Mihir Dave solution takes care of the change from AUD to SGD and any other of the 200 world currencies we are using. The above code breaks for that reason..

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.