使用真实示例使用Newtonsoft.Json库。 第一部分

如果您正在阅读本文,那么您很可能已经知道JSON是什么,并且您熟悉下面的图片。 但是无论如何,我建议您访问此页面(如果您以前从未到过此页面) ,并且在阅读之前,建议您熟悉一下在C#中使用JSON表示法的一般原理,例如, 在此链接



我想指出的是,本说明并不伪装成对该主题的任何完整披露。 本文的目的是构造和保留我在使用Newtonsoft.Json库时使用的那些开发。

问题陈述


总的来说,在本文的框架内,如何获取原始数据进行解析并不是很重要,但是,这种解释肯定会促进对材料的理解。 因此,主要任务是实现EXMO cryptoexchange API的功能。 为简单起见,我们将主要使用公共接口(Public API)。 在这种情况下,信息请求将看起来像站点的常规页面地址。 要发送请求,请使用System.Net.Http命名空间的HttpClient类:

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

通过单击链接https://api.exmo.com/v1/trades/?pair=BTC_USD可以查看该程序的结果。 如果将这些数据加载到JSON C#Class Generator中 ,将为反序列化提供以下类结构:

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

应该注意的是,加密交换“交易”功能本身允许您一次请求有关多个货币对的信息。 并且在要求的情况下

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

类的结构已经看起来像这样:

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

显然,您无法为每种货币对组合准备课程,这意味着您需要以某种方式摆脱困境。

不必这样做。
令人惊讶的是,几乎不可能在俄语互联网上找到有关使用JSON表示法的优秀文章。 结果,可以在GitHub上找到的那些EXMO API实现以某种方式包含使用split,trim等等对原始数据结构的操作。

我必须承认,我还首先发明了自行车并自行实现了解析。 尽管代码绝对有效,但这是您无法执行此操作的一个很好的示例。


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


JSON对象(JObject类)


JSON对象是键/值对的无序集合。 对象以“ {”(大括号的开头)开始,以“}”(大括号的结尾)结束。 每个名称后跟:(冒号),键/值对之间用逗号分隔。



从JSON C#类生成器先前向我们提出的结构中,我们看到,对于每个货币对,我们都有6个常量字段。 将它们包装在单独的类中,并将其命名为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; } } 

为了能够从交换的动态变化的数据结构中“抓住”这些字段的集合,您需要更详细地了解newtosoft.json库中可用的数据类型。 更具体地说,在newtonsoft.json.linq命名空间中。

要使用该库,必须先安装它。
要在Visual Studio中安装该库,您只需搜索NuGet。
在解决方案资源管理器中右键单击解决方案,然后选择“管理解决方案的NuGet软件包...”(管理解决方案的NuGet软件包...“)。



接下来,单击“浏览”,然后在搜索栏中输入newtosoft.json。 我们在解决方案前打勾,然后单击“安装”(“安装”)。



安装库之后,newtosoft.json.linq命名空间可用于连接到项目:

 using Newtonsoft.Json.Linq; 

Newtosoft.json.linq使用抽象的JToken类表示数据,从中继承JValue (表示简单值)和JContainer (表示结构)类。 反过来,结构可以是JArray (数组), JConstructor (构造函数), JObject (对象)或JProperty (属性)。

JArray和JObject类具有Parse方法,该方法使您可以将JSON数据从常规字符串转换为相应的对象。 因此,如果我们对Exmo trades函数的数据结构使用JObject.Parse(String)方法:

 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类型):



现在,可以通过键“ BTC_USD”和“ USD_ETH”使用交易列表。 例如,使用货币对“ BTC_USD”进行的交易:



然后,我们只需要将数据转换为便于工作的类型,例如 清单<订单> 使用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>>(); 

要么将整个结构转换为类型 字典<string,列表<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>>()); 

JSON数组(JArray类)


JSON数组是值的有序集合。 数组以“ [”(方括号)开始,以“]”(方括号)结束。 值用逗号分隔。

通过点击链接https://api.exmo.com/v1/currency可以看到JSON数组的样子。 如果您尝试将其转换为JObject,就像我们对上一个请求所做的那样:

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

我们将得到一个Newtonsoft.Json.JsonReaderException异常,告诉我们正在转换的数据不是对象。



数组必须转换为特殊的JArray类型,就像JObject一样,它是从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); 

在解析的情况下,事先不知道初始结构,或者需要具有处理两种类型的数据的能力-您可以将JContainer或JToken指定为转换后的对象的类型,然后在解析期间,数据将隐式转换为所需的类型。

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

JSON值(JValue类)


根据JSON格式描述,该值可以是双引号字符串,数字,true,false,null, 对象数组 。 这些结构可以嵌套。 在newotnsoft.json的实现中,仅简单类型的对象可以是一个值。 尝试将JArray转换为JValue将导致“ System.InvalidCastException”异常。

作为newtonsoft.json库中使用特定值(JValue类)的入门资料,文档 两次的示例非常适合。

来自交易所的数据的用法示例:

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

在本文的第二部分,我将更详细地描述准备用于解析数据的类的可能性,以及使用DateTime数据类型的一些功能。

程序的全文。
 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>>>(); } } } 


有关该库的最完整,最详细的信息始终可以在官方文档中找到。

Source: https://habr.com/ru/post/zh-CN481514/


All Articles