Travailler avec la bibliothèque Newtonsoft.Json avec un exemple réel. Partie 1

Si vous lisez cet article, vous savez probablement ce qu'est JSON et l'image ci-dessous vous est familière. Mais dans tous les cas, je vous conseille de visiter cette page si vous n'y avez pas déjà été, ainsi qu'avant de lire il est conseillé de vous familiariser avec les principes généraux du travail avec la notation JSON en C #, par exemple, sur ce lien .



Je tiens à noter que cette note ne prétend pas être une divulgation complète du sujet. Le but de ce texte est de structurer et de préserver les développements que j'ai utilisés lors de l'utilisation de la bibliothèque Newtonsoft.Json.

Énoncé du problème


Dans l'ensemble, dans le cadre de l'article, il n'est pas si important de savoir comment les données initiales ont été obtenues pour l'analyse, cependant, cette explication facilitera certainement la perception du matériau. Ainsi, la tâche principale consiste à implémenter les fonctions de l'API EXMO cryptoexchange . Par souci de simplicité, nous travaillerons principalement avec l'interface publique (API publique). Dans ce cas, la demande d'informations ressemblera à une adresse de page régulière d'un site. Pour envoyer des demandes, la classe HttpClient de l'espace de noms System.Net.Http est utilisée:

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

Le résultat de ce programme peut être vu en cliquant sur le lien https://api.exmo.com/v1/trades/?pair=BTC_USD . Si vous chargez ces données dans le générateur de classe JSON C # , la structure de classe suivante nous sera proposée pour la désérialisation:

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

Il convient de noter que la fonction «métiers» de crypto-échange vous permet en soi de demander des informations sur plusieurs paires de devises à la fois. Et en cas de demande

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

La structure de classe ressemblera déjà à ceci:

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

De toute évidence, vous ne pouvez pas préparer de cours pour chaque combinaison de paires de devises, ce qui signifie que vous devez en quelque sorte sortir.

Comment le faire n'est pas nécessaire.
Étonnamment, il est presque impossible de trouver de bons articles sur l'utilisation de la notation JSON sur Internet en russe. En conséquence, les implémentations de l'API EXMO qui peuvent être trouvées sur GitHub contiennent en quelque sorte des manipulations avec la structure de données d'origine à l'aide de split s, trim s et similaires.

Je dois admettre que j'ai aussi d'abord inventé un vélo et mis en œuvre l'analyse par moi-même. Malgré le fait que le code fonctionne absolument, c'est un excellent exemple de la façon dont vous NE POUVEZ PAS le faire.


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


Objets JSON (classe JObject)


L'objet JSON est un ensemble non ordonné de paires clé / valeur. Un objet commence par '{' (une accolade ouvrante) et se termine par '}' (une accolade fermante). Chaque nom est suivi de: (deux points), les paires clé / valeur sont séparées par une virgule.



D'après la structure qui nous a été proposée précédemment par JSON C # Class Generator, nous voyons que pour chaque paire de devises, nous avons 6 champs constants. Enveloppez-les dans une classe séparée et appelez-la Order.

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

Pour pouvoir «saisir» un ensemble de ces champs dans la structure de données changeante de manière dynamique de l'échange, vous devez comprendre plus en détail les types de données disponibles dans la bibliothèque newtosoft.json. Plus précisément, dans l'espace de noms newtonsoft.json.linq.

Pour travailler avec la bibliothèque, vous devez l'installer.
Pour installer la bibliothèque dans Visual Studio, vous pouvez simplement rechercher NuGet.
Cliquez avec le bouton droit sur la solution dans l'explorateur de solutions et sélectionnez "Gérer les packages NuGet pour la solution ..." (Gérer les packages NuGet pour la solution ... ").



Ensuite, cliquez sur «Parcourir» et entrez newtosoft.json dans la barre de recherche. Nous mettons une coche devant notre solution et cliquez sur "Installer" ("Installer").



L'espace de noms newtosoft.json.linq, après l'installation de la bibliothèque, devient disponible pour la connexion au projet:

 using Newtonsoft.Json.Linq; 

Newtosoft.json.linq utilise la classe abstraite JToken pour représenter les données, dont les classes JValue (pour représenter les valeurs simples) et JContainer (pour représenter les structures) sont héritées. Les structures, à leur tour, peuvent être un JArray (tableau), JConstructor (constructeur), JObject (objet) ou JProperty (propriété).

Les classes JArray et JObject ont une méthode Parse qui vous permet de convertir les données JSON d'une chaîne régulière en objets correspondants. Donc, si nous utilisons la méthode JObject.Parse (String) pour la structure de données de la fonction métiers 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); 

nous verrons une structure de deux éléments, chacun représentant une paire clé-valeur. Dans ce cas, la clé sera le nom de la paire de devises (type String) et la valeur sera la liste des transactions (type JToken):



Désormais, les listes de transactions sont à notre disposition avec les clés "BTC_USD" et "USD_ETH". Par exemple, les transactions sur la paire de devises "BTC_USD":



Ensuite, nous avons juste besoin de traduire les données en un type pratique pour le travail, par exemple Liste <Ordre> en utilisant la méthode 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>>(); 

soit convertir toute la structure en type Dictionnaire <chaîne, Liste <Ordre>> :

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

Tableaux JSON (classe JArray)


Le tableau JSON est une collection ordonnée de valeurs. Un tableau commence par «[» (le crochet carré d'ouverture) et se termine par «]» (le crochet carré de fermeture). Les valeurs sont séparées par une virgule.

À quoi ressemble le tableau JSON peut être vu en suivant le lien https://api.exmo.com/v1/currency . Si vous essayez de le convertir en JObject, comme nous l'avons fait avec la demande précédente:

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

nous obtiendrons une exception Newtonsoft.Json.JsonReaderException nous indiquant que les données en cours de conversion ne sont pas un objet.



Les tableaux doivent être convertis en un type JArray spécial, qui, comme JObject, hérite de 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); 

Dans le cas de l'analyse, la structure initiale n'est pas connue à l'avance, ou la capacité de traiter les deux types de données est requise - vous pouvez spécifier JContainer ou JToken comme type de l'objet converti, puis lors de l'analyse, les données seront implicitement converties au type souhaité.

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

Valeurs JSON (classe JValue)


Selon la description du format JSON, la valeur peut être une chaîne entre guillemets doubles, un nombre, true, false, null, un objet ou un tableau . Ces structures peuvent être imbriquées. Dans l'implémentation de newotnsoft.json, seuls les objets de types simples peuvent être une valeur. Toute tentative de conversion d'un JArray en JValue entraînera une exception «System.InvalidCastException».

En tant que matériel d'introduction sur l'utilisation de valeurs spécifiques (la classe JValue) dans la bibliothèque newtonsoft.json, les exemples de la documentation une fois et deux sont bien adaptés.

Exemple d'utilisation des données de l'échange:

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

Dans la deuxième partie de l'article, je décrirai plus en détail les possibilités de préparation d'une classe pour l'analyse des données, ainsi que certaines fonctionnalités du travail avec le type de données DateTime.

Le texte intégral du programme.
 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>>>(); } } } 


Les informations les plus complètes et détaillées sur la bibliothèque se trouvent toujours dans la documentation officielle .

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


All Articles