Trabalhando com a biblioteca Newtonsoft.Json com um exemplo real. Parte 1

Se você ler este artigo, provavelmente estará ciente do que é o JSON e a imagem abaixo lhe é familiar. Mas, em qualquer caso, aconselho que você visite esta página, se você ainda não esteve lá antes, e é recomendável que você se familiarize com os princípios gerais de trabalhar com a notação JSON em C #, por exemplo, neste link .



Quero observar que esta nota não pretende ser uma divulgação completa do tópico. O objetivo deste texto é estruturar e preservar os desenvolvimentos que usei ao trabalhar com a biblioteca Newtonsoft.Json.

Declaração do problema


De um modo geral, na estrutura do artigo não é tão importante como os dados iniciais foram obtidos para análise, no entanto, essa explicação certamente facilitará a percepção do material. Portanto, a principal tarefa é implementar as funções da API de troca de criptografia EXMO . Para simplificar, trabalharemos principalmente com a Interface pública (API pública). Nesse caso, a solicitação de informações será semelhante ao endereço de página normal de um site. Para enviar solicitações, a classe HttpClient do espaço para nome System.Net.Http é usada:

HttpClient httpClient = new HttpClient(); string request = "https://api.exmo.com/v1/trades/?pair=BTC_USD"; HttpResponseMessage response = (await httpClient.GetAsync(request)).EnsureSuccessStatusCode(); string responseBody = await response.Content.ReadAsStringAsync(); 

O resultado deste programa pode ser visto clicando no link https://api.exmo.com/v1/trades/?pair=BTC_USD . Se você carregar esses dados no JSON C # Class Generator , ofereceremos a seguinte estrutura de classe para desserialização:

  public class BTCUSD { public int trade_id { get; set; } public string type { get; set; } public string quantity { get; set; } public string price { get; set; } public string amount { get; set; } public int date { get; set; } } public class RootObject { public List<BTCUSD> BTC_USD { get; set; } } 

Deve-se notar que a própria função de "negociações" de troca de criptografia permite solicitar informações sobre vários pares de moedas ao mesmo tempo. E em caso de solicitação

 string request = "https://api.exmo.com/v1/trades/?pair=BTC_USD,ETH_USD"; 

A estrutura da classe já terá a seguinte aparência:

  public class BTCUSD { public int trade_id { get; set; } public string type { get; set; } public string quantity { get; set; } public string price { get; set; } public string amount { get; set; } public int date { get; set; } } public class ETHUSD { public int trade_id { get; set; } public string type { get; set; } public string quantity { get; set; } public string price { get; set; } public string amount { get; set; } public int date { get; set; } } public class RootObject { public List<BTCUSD> BTC_USD { get; set; } public List<ETHUSD> ETH_USD { get; set; } } 

Obviamente, você não pode preparar aulas para cada combinação de pares de moedas, o que significa que você precisa sair de alguma forma.

Como fazer isso não é necessário.
Surpreendentemente, é quase impossível encontrar bons artigos sobre como trabalhar com a notação JSON na Internet em russo. Como resultado, as implementações da API EXMO que podem ser encontradas no GitHub de alguma forma contêm manipulações com a estrutura de dados original usando split s, trim se similares.

Devo admitir que também inventei uma bicicleta e implementei a análise por conta própria. Apesar do fato de o código estar absolutamente funcionando, este é um ótimo exemplo de como você NÃO PODE fazê-lo.


 LinkedList<OrderInform> loi = new LinkedList<OrderInform>(); try { string[] json = answer.Split(new char[] { '{', '}' }); foreach (var item in json) { if (item.Length > 20) { string[] trade = item.Split(new char[] { ',' }); if (trade.Length > 5) { string t_id = trade[0].Split(new char[] { ':' })[1].Trim('"'); string t_type = trade[1].Split(new char[] { ':' })[1].Trim('"'); string t_quantity = trade[2].Split(new char[] { ':' })[1].Trim('"') .Replace(".", ","); string t_price = trade[3].Split(new char[] { ':' })[1].Trim('"') .Replace(".", ","); string t_amount = trade[4].Split(new char[] { ':' })[1].Trim('"') .Replace(".", ","); string t_date_time = trade[5].Split(new char[] { ':' })[1].Trim('"'); loi.AddLast(new OrderInform(pair, Convert.ToInt32(t_id), t_type, Convert.ToDouble(t_quantity), Convert.ToDouble(t_price), Convert.ToDouble(t_amount), (new DateTime(1970, 1, 1, 0, 0, 0, 0)) .AddSeconds(Convert.ToInt32(t_date_time)))); } } } return loi; } catch (Exception ex) { return new LinkedList<OrderInform>(); } 


Objetos JSON (classe JObject)


O objeto JSON é um conjunto não ordenado de pares de chave / valor. Um objeto começa com '{' (uma chave de abertura) e termina com '}' (uma chave de fechamento). Cada nome é seguido por: (dois pontos), pares de chave / valor são separados por vírgula.



A partir da estrutura que nos foi proposta anteriormente pelo JSON C # Class Generator, vemos que, para cada par de moedas, temos 6 campos constantes. Envolva-os em uma classe separada e chame-a de Ordem.

  class Order { public int trade_id { get; set; } public string type { get; set; } public double quantity { get; set; } public double price { get; set; } public double amount { get; set; } public int date { get; set; } } 

Para poder "pegar" um conjunto desses campos da estrutura de dados em mudança dinâmica da troca, você precisa entender com mais detalhes os tipos de dados disponíveis na biblioteca newtosoft.json. Mais especificamente, no espaço para nome newtonsoft.json.linq.

Para trabalhar com a biblioteca, você deve instalá-lo.
Para instalar a biblioteca no Visual Studio, você pode simplesmente pesquisar no NuGet.
Clique com o botão direito do mouse na solução no Solution Explorer e selecione "Gerenciar pacotes NuGet para a solução ..." (Gerenciar pacotes NuGet para a solução ... ").



Em seguida, clique em "Procurar" e digite newtosoft.json na barra de pesquisa. Colocamos uma marca na frente da nossa solução e clicamos em "Instalar" ("Instalar").



O namespace newtosoft.json.linq, depois de instalar a biblioteca, fica disponível para conexão com o projeto:

 using Newtonsoft.Json.Linq; 

Newtosoft.json.linq usa a classe JToken abstrata para representar dados, da qual as classes JValue (para representar valores simples) e JContainer (para representar estruturas) são herdadas. As estruturas, por sua vez, podem ser um JArray (matriz), JConstructor (construtor), JObject (objeto) ou JProperty (propriedade).

As classes JArray e JObject têm um método Parse que permite converter dados JSON de uma sequência regular para os objetos correspondentes. Portanto, se usarmos o método JObject.Parse (String) para a estrutura de dados da função de negociação Exmo:

 HttpClient httpClient = new HttpClient(); string request = "https://api.exmo.com/v1/trades/?pair=BTC_USD,ETH_USD"; HttpResponseMessage response = (await httpClient.GetAsync(request)).EnsureSuccessStatusCode(); string responseBody = await response.Content.ReadAsStringAsync(); JObject jObject = JObject.Parse(responseBody); 

veremos uma estrutura de dois elementos, cada um dos quais representa um par de valores-chave. A chave nesse caso será o nome do par de moedas (tipo String) e o valor será a lista de transações (tipo JToken):



Agora, as listas de transações estão disponíveis para nós com as chaves "BTC_USD" e "USD_ETH". Por exemplo, transações no par de moedas "BTC_USD":



Depois, precisamos apenas converter os dados em um tipo conveniente para o trabalho, por exemplo Listar <Order> usando o método ToObject <> ():

 HttpClient httpClient = new HttpClient(); string request = "https://api.exmo.com/v1/trades/?pair=BTC_USD,ETH_USD"; HttpResponseMessage response = (await httpClient.GetAsync(request)).EnsureSuccessStatusCode(); string responseBody = await response.Content.ReadAsStringAsync(); JObject jObject = JObject.Parse(responseBody); JToken list = jObject["BTC_USD"]; List<Order> trades = list.ToObject<List<Order>>(); 

converter a estrutura inteira para digitar Dicionário <string, Lista <Order>> :

 HttpClient httpClient = new HttpClient(); string request = "https://api.exmo.com/v1/trades/?pair=BTC_USD,ETH_USD"; HttpResponseMessage response = (await httpClient.GetAsync(request)).EnsureSuccessStatusCode(); string responseBody = await response.Content.ReadAsStringAsync(); JObject jObject = JObject.Parse(responseBody); Dictionary<string, List<Order>> trades = new Dictionary<string, List<Order>>(); foreach (KeyValuePair<string, JToken> obj in jObject) trades.Add(obj.Key, obj.Value.ToObject<List<Order>>()); 

Matrizes JSON (classe JArray)


A matriz JSON é uma coleção ordenada de valores. Uma matriz começa com '[' (o colchete de abertura) e termina com ']' (o colchete de fechamento). Os valores são separados por vírgula.

A aparência da matriz JSON pode ser vista seguindo o link https://api.exmo.com/v1/currency . Se você tentar convertê-lo em um JObject, como fizemos com a solicitação anterior:

 HttpClient httpClient = new HttpClient(); string request = "https://api.exmo.com/v1/currency"; HttpResponseMessage response = (await httpClient.GetAsync(request)).EnsureSuccessStatusCode(); string responseBody = await response.Content.ReadAsStringAsync(); JObject jObject = JObject.Parse(responseBody); 

obteremos uma exceção Newtonsoft.Json.JsonReaderException nos dizendo que os dados que estão sendo convertidos não são um objeto.



As matrizes devem ser convertidas em um tipo JArray especial, que, como JObject, herda do JContainer.

 HttpClient httpClient = new HttpClient(); string request = "https://api.exmo.com/v1/currency"; HttpResponseMessage response = (await httpClient.GetAsync(request)).EnsureSuccessStatusCode(); string responseBody = await response.Content.ReadAsStringAsync(); JObject jObject = JObject.Parse(responseBody); JArray jArray = JArray.Parse(responseBody); 

No caso de análise, a estrutura inicial não é conhecida antecipadamente ou a capacidade de processar os dois tipos de dados é necessária - você pode especificar JContainer ou JToken como o tipo do objeto convertido e, durante a análise, os dados serão implicitamente convertidos no tipo desejado.

 HttpClient httpClient = new HttpClient(); string request = "https://api.exmo.com/v1/currency"; HttpResponseMessage response = (await httpClient.GetAsync(request)).EnsureSuccessStatusCode(); string responseBody = await response.Content.ReadAsStringAsync(); JToken jArray = JToken.Parse(responseBody ); //    JArray List<string> list = jArray.ToObject<List<string>>(); request = "https://api.exmo.com/v1/trades/?pair=BTC_USD,ETH_USD"; HttpResponseMessage response = (await httpClient.GetAsync(request)).EnsureSuccessStatusCode(); string responseBody = await response.Content.ReadAsStringAsync(); JToken jObject = JToken.Parse(responseBody ); //    JObject Dictionary<string, List<Order>> dict = jObject.ToObject<Dictionary<string, List<Order>>>(); 

Valores JSON (classe JValue)


De acordo com a descrição do formato JSON, o valor pode ser uma sequência de aspas duplas, um número, verdadeiro, falso, nulo, um objeto ou uma matriz . Essas estruturas podem ser aninhadas. Na implementação do newotnsoft.json, apenas objetos de tipos simples podem ser um valor. Tentar converter um JArray em um JValue resultará em uma exceção "System.InvalidCastException".

Como material introdutório sobre o trabalho com valores específicos (a classe JValue) na biblioteca newtonsoft.json, exemplos da documentação uma e duas vezes são adequados.

Exemplo de uso para dados da troca:

 HttpClient httpClient = new HttpClient(); string request = "https://api.exmo.com/v1/currency"; HttpResponseMessage response = (await httpClient.GetAsync(request)).EnsureSuccessStatusCode(); string responseBody = await response.Content.ReadAsStringAsync(); JArray jArray = JArray.Parse(responseBody ); foreach (JValue value in jArray) { string s = (string)value; } 

Na segunda parte do artigo, descreverei com mais detalhes as possibilidades de preparar uma classe para analisar dados, bem como alguns recursos do trabalho com o tipo de dados DateTime.

O texto completo do programa.
 using System.Threading.Tasks; using System.Collections.Generic; using System.Net.Http; using Newtonsoft.Json.Linq; namespace JSONObjects { class Order { public int trade_id { get; set; } public string type { get; set; } public double quantity { get; set; } public double price { get; set; } public double amount { get; set; } public int date { get; set; } } class Program { public static async Task Main(string[] args) { HttpClient httpClient = new HttpClient(); string request = "https://api.exmo.com/v1/currency"; HttpResponseMessage response = (await httpClient.GetAsync(request)).EnsureSuccessStatusCode(); string responseBody = await response.Content.ReadAsStringAsync(); JToken jArray = JToken.Parse(responseBody); //    JArray List<string> list = jArray.ToObject<List<string>>(); request = "https://api.exmo.com/v1/trades/?pair=BTC_USD,ETH_USD"; response = (await httpClient.GetAsync(request)).EnsureSuccessStatusCode(); responseBody = await response.Content.ReadAsStringAsync(); JToken jObject = JToken.Parse(responseBody); //    JObject Dictionary<string, List<Order>> dict = jObject.ToObject<Dictionary<string, List<Order>>>(); } } } 


As informações mais completas e detalhadas sobre a biblioteca sempre podem ser encontradas na documentação oficial .

Source: https://habr.com/ru/post/pt481514/


All Articles