0

I've received a JSON from a Web API to build an MVC application. (https://api.coingecko.com/api/v3/exchange_rates)

The structure look's like this:

{
  "rates": {
    "btc": {
      "name":"Bitcoin",
      "unit":"BTC",
      "value":1.0,
      "type":"crypto"
    },
    "eth":{
      "name":"Ether",
      "unit":"ETH",
      "value":12.954,
      "type":"crypto"
    },...

When I use "Paste JSON as Classes" it's generate a huge list of classes and a Root Object with a lot of properties.

I'm deserializing it like this:

Rootobject myDeserializedClass = JsonConvert.DeserializeObject<Rootobject>(jsonstring)

There's a better way of doing that?

Edit:

I was using a different class for each of the objects:

Exemple:

public class Btc
    {
        public string name { get; set; }
        public string unit { get; set; }
        public double value { get; set; }
        public string type { get; set; }
    }

    public class Eth
    {
        public string name { get; set; }
        public string unit { get; set; }
        public double value { get; set; }
        public string type { get; set; }
    }

    public class Ltc
    {
        public string name { get; set; }
        public string unit { get; set; }
        public double value { get; set; }
        public string type { get; set; }
    }

I'm beginner C# student and didn't thought about using Dictionary. A had a code with 66 different classes and a method as below:

var requisicaoWeb = WebRequest.CreateHttp("https://api.coingecko.com/api/v3/exchange_rates");
requisicaoWeb.Method = "Get";
requisicaoWeb.UserAgent = "RequisicaoWebDemo";

using (var resposta = requisicaoWeb.GetResponse())
{
    var streamDados = resposta.GetResponseStream();
    StreamReader reader = new StreamReader(streamDados);
    object objResponse = reader.ReadToEnd();
    var jsonstring = objResponse.ToString().Replace("{\"rates\":", "");
    jsonstring = jsonstring.Remove(jsonstring.Length - 1);
    streamDados.Close();
    resposta.Close();
    Rootobject myDeserializedClass = JsonConvert.DeserializeObject<Rootobject>(jsonstring);
    
    foreach (var p in myDeserializedClass.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any()))
    {      
        var test = (p.GetValue(myDeserializedClass));
        if(test!=null)
        {
         string lol = test.ToString().ToLower();
            jsonstring = jsonstring.Replace($"\"{lol}\":", "");
        }         
    }

    jsonstring = jsonstring.Remove(jsonstring.Length - 1)
                           .Remove(0,1)
                           .Replace($"\"try\":", "")
                           .Insert(0, "[");
    jsonstring = jsonstring.Insert(jsonstring.Length, "]");   
}
Will I'm
  • 31
  • 5
  • Please add your code for the object you are deserializing into to your question. Are you getting an error or just seeking "advice/opinions here? What is your actual question other than "a better way" – Mark Schultheiss Jan 16 '22 at 01:35
  • @MarkSchultheiss, I wasn't getting an error, but the code was getting too complicated the way it was. – Will I'm Jan 16 '22 at 01:59
  • 1
    You could also create a base class with those properties and inherit that – Mark Schultheiss Jan 16 '22 at 02:18

2 Answers2

1

The structure of the json in rates can be deserialized to a Dictionary<string, CustomClass>. You can deserialize the json using the following classes:

public class RatesData
{
    public Dictionary<string, CryptoData> Rates { get;set;}
}

public class CryptoData
{
    public string Name { get;set;}
    public string Unit { get;set;}
    public string Value { get;set;}
    public string Type { get;set;}
}

And deserialize (using Newtonsoft.Json):

var model = JsonConvert.DeserializeObject<RatesData>(json);

Demo

haldo
  • 14,512
  • 5
  • 46
  • 52
0

You can deserialize your json to Dictionary, but it is much more safer to use a list of rates, since it is a typed class. Plus you can use much more LINQ functions

var parsedRates = (JObject)JObject.Parse(json)["rates"];

List<Rate> rates = parcedRates.Properties().Select(p => ConvertRate(p)).ToList();

private Rate ConvertRate(JProperty prop)
{
    var rate= prop.Value.ToObject<Rate>();
    rate.Key = prop.Name;
    return rate;
}

output

[
  {
    "key": "btc",
    "name": "Bitcoin",
    "unit": "BTC",
    "value": 1.0,
    "type": "crypto"
  },
  {
    "key": "eth",
    "name": "Ether",
    "unit": "ETH",
    "value": 12.954,
    "type": "crypto"
  }
]

class

public partial class Rate
{
    [JsonProperty("key")]
    public string Key { get; set; }

    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("unit")]
    public string Unit { get; set; }

    [JsonProperty("value")]
    public double Value { get; set; }

    [JsonProperty("type")]
    public string Type { get; set; }
}
Serge
  • 40,935
  • 4
  • 18
  • 45
  • In this way you are loosing the key (and the unit doesn't always have to be the same string as the key) – Markus Safar Jan 16 '22 at 03:24
  • @MarkusSafar It is much easier to find by key using linq – Serge Jan 16 '22 at 03:59
  • Now you have changed your code, at least the key is at accessible ;-) But why is it "easier" in your opinion than accessing something in a dictionary? – Markus Safar Jan 16 '22 at 12:23
  • @MarkusSafar In my answer is written that it is safer, since it is fully typed and fully relational. Everthing is in one level and in one class. Dictionay feels more hirarchial for me. – Serge Jan 16 '22 at 13:23
  • I absolutly agree that fully typed is very good and import. On the other side the dictionary provides a `ContainsKey` method so from the point of "beeing safe" I do not see any difference. For the rest - I guess it's just a matter of preference (LINQ over dictionary) ;-) – Markus Safar Jan 16 '22 at 13:58
  • @MarkusSafar Dictionary is usually used to keep data like appsettings.json since all this data is allways different, and it is hard to create a class. But for the most another application data collections are used. Even this data that looks like read only, needs to be shown in tables or charts. All controlls of this kind need a list as a data source. I am not taking even that I've never seen dictionary as a View Model. – Serge Jan 16 '22 at 14:15