0

Well, I'm new to programming, and I have a problem.

This is my class Valores

public class Valores
    {
        [JsonProperty("nome")]
        public string Nome { get; set; }
        [JsonProperty("valor")]
        public double Valor { get; set; }
        [JsonProperty("ultima_consulta")]
        public int UltimaConsulta { get; set; }
        [JsonProperty("fonte")]
        public string Fonte { get; set; }
    }

And this is my method where I get and deserialize my Json

public static async Task<Valores> GetAsync()
    {
        Valores valores = null;

            using (var client = new HttpClient())
            {
                var json = await client.GetStringAsync("http://api.promasters.net.br/cotacao/v1/valores");
                valores = JsonConvert.DeserializeObject<Valores>(json);
            }

        return valores;
    }

This is json that the way: "http://api.promasters.net.br/cotacao/v1/valores" returns.

{
  "status": true,
  "valores": {
    "USD": {
      "nome": "Dólar",
      "valor": 3.0717,
      "ultima_consulta": 1490040302,
      "fonte": "UOL Economia - http://economia.uol.com.br/"
    },
    "EUR": {
      "nome": "Euro",
      "valor": 3.3002,
      "ultima_consulta": 1490040302,
      "fonte": "UOL Economia - http://economia.uol.com.br/"
    },
    "ARS": {
      "nome": "Peso Argentino",
      "valor": 0.1965,
      "ultima_consulta": 1490040302,
      "fonte": "UOL Economia - http://economia.uol.com.br/"
    },
    "GBP": {
      "nome": "Libra Esterlina",
      "valor": 3.7966,
      "ultima_consulta": 1490040302,
      "fonte": "UOL Economia - http://economia.uol.com.br/"
    },
    "BTC": {
      "nome": "Bitcoin",
      "valor": 3472,
      "ultima_consulta": 1490067603,
      "fonte": "Mercado Bitcoin - http://www.mercadobitcoin.com.br/"
    }
  }
}

I do not know what I did wrong, because this

var json = await client.GetStringAsync("http://api.promasters.net.br/cotacao/v1/valores");

It was to receive Json in string, but is not receiving anything, it's like an empty string.

dehoziiN
  • 5
  • 2

3 Answers3

1

I experimented a bit, and it appears the web site requires the user agent request string to be set to something in order for JSON to be returned. And, by something, I mean that the string "something" seems to work, as does the string "Wget/1.11.4". You should check the documentation (Portugese) to make sure there are no restrictions on programmatic access to this site, and comply with those access restrictions (if any).

Also, your data model does not reflect your JSON. You need a higher level root object as follows:

public class RootObject
{
    public RootObject() { this.valores = new Dictionary<string, Valores>(); }

    public bool status { get; set; }
    public Dictionary<string, Valores> valores { get; set; }
}

Here is a sample fiddle that successfully downloads and deserializes JSON from the site by setting the user agent. It uses WebClient since that's what seems to be available on https://dotnetfiddle.net/:

public static async Task<RootObject> GetAsync()
{
    using (var client = new WebClient())
    {
        client.Headers["User-Agent"] = "something";
        var json = await client.DownloadStringTaskAsync(@"http://api.promasters.net.br/cotacao/v1/valores");
        var root = JsonConvert.DeserializeObject<RootObject>(json);
        return root;
    }   
}

And for HttpClient I think it should be (untested):

public static async Task<RootObject> GetAsync()
{
    var client = new HttpClient();

    client.DefaultRequestHeaders.Add("User-Agent", "something");
    var json = await client.GetStringAsync("http://api.promasters.net.br/cotacao/v1/valores");
    return JsonConvert.DeserializeObject<RootObject>(json);
}

See also this post for a discussion of whether to dispose the HttpClient.

dbc
  • 104,963
  • 20
  • 228
  • 340
0

There issue here is that the deserialised json is not correctly getting mapped to a an object. Try to create a wrapper class over your model (Valores) and then try to map.

public class Valores
{
    [JsonProperty("nome")]
    public string Nome { get; set; }
    [JsonProperty("valor")]
    public double Valor { get; set; }
    [JsonProperty("ultima_consulta")]
    public int UltimaConsulta { get; set; }
    [JsonProperty("fonte")]
    public string Fonte { get; set; }
}

public class ValoresList
{
    public boolean status { get; set; }
    public Valores USD { get; set; }
    public Valores EUR { get; set; }
    public Valores ARS { get; set; }
    public Valores GBP { get; set; }
    public Valores BTC { get; set; }
}

And then map the wrapper class to the deserialised json.

public static async Task<ValoresList> GetAsync()
{
    ValoresList valores = null;

    using (var client = new HttpClient())
    {
        var json = await client.GetStringAsync("http://api.promasters.net.br/cotacao/v1/valores");
        valores = JsonConvert.DeserializeObject<ValoresList>(json);
    }

    return valores;
} 
TejSoft
  • 3,213
  • 6
  • 34
  • 58
0

The problem is the json returned contains a collection of Valores in a dictionary, you're trying to map the response to a single Valore object.

Your container wants to look like this. The key for the dictionary is the string representation of the currency.

class Container
{
    public bool Status { get; set; }
    public Dictionary<string, ValorInfo> Valores { get; set; }
}

Your Valor class is good as is, I renamed it to prevent a conflict on the class name to Valor property.

class ValorInfo
{
    [JsonProperty("nome")]
    public string Nome { get; set; }
    [JsonProperty("valor")]
    public double Valor { get; set; }
    [JsonProperty("ultima_consulta")]
    public int UltimaConsulta { get; set; }
    [JsonProperty("fonte")]
    public string Fonte { get; set; }
}

Finally this is how you use it, props to @dbc for spotting the user-agent requirement, that had me stumped!

async void Main()
{
    using (var client = new HttpClient())
    {
        client.DefaultRequestHeaders.Add("Accept", "application/json");
        client.DefaultRequestHeaders.Add("User-Agent", "linqpad");

        var response = await client.GetAsync("http://api.promasters.net.br/cotacao/v1/valores");
        response.EnsureSuccessStatusCode();

        var container = await response.Content.ReadAsAsync<Container>();

        // do stuff with container...
    }
}