О том, как использовать Json в C#

JSON — простой, основанный на использовании текста, способ хранить и передавать структурированные данные. Сегодня рассмотри, как попросить Json у сайта и что с ним делать?
Сначала несколько определений, позаимствованных мною с просторов Интернета:
Сериализация — это процесс перевода структуры данных в последовательность битов, или же в другую структуру данных, которую удобно хранить, передавать (этот процесс в статье подробно мы не будем рассматривать)
Десериализация — это обратный процесс. Процесс преобразования сериализованных данных в структуру данных.
Теперь рассмотрим практический пример:
На первом этапе в студии из NuGet скачиваем — Newtonsoft.Json, указываем в поиске — Json, находим — Newtonsoft.Json (его мы и будем использовать)
Затем прописываем — using Newtonsoft.Json.Linq;
Теперь нам необходимо найти страницу, с которой берем json (то есть берем страницу, где только json, и дальше выбираем один из вариантов):
- Для тех, кто старается сделать быстро: копируем весь текст json со страницы, переходим на специальный сайт, который экономит наше время тем, что строит за нас классы (например — http://json2csharp.com/#), вставляем json на этом сайте. И одним нажатием на кнопку – получаем результат (его и копируем в студию).
Как можно улучшить выгрузку:
- Проверить страницы с json и дописать переменные, если их не хватает
- Проверить название классов (часто встречается, что несколько классов с одним именем, если разные страницы разбираем в одной программе)
2. Для тех, кто желает погрузиться в разработку:
создаете открытый класс
public class Data
Делаете описание класса с наймингами, как в Json и получаем то же самое, что и в первом случае:
< public int a < get; set; >public string b < get; set; >public double c < get; set; >public List d < get; set; >>
3. Если информации не много, то классы можно не использовать.
Дальше получаем текст и вставляем его в объект jsona:
JObject jObject = JObject.Parse(Text);
1. Если выбрали 3, то можно указать путь и конвертнуть в тот тип данных, который нужен:
Convert.ToInt16(jObject["data"]["data2"])
2. Если выбрали 1 или 2 вариант, то мы производим десериализацию json в list,
List list = jObject.ToObject>(); Кстати, тут тоже можно указывать путь: jObject["data"]["data2"].ToObject>();
Вот такими методами мы «подружили» Json и C#.
Что такое » newtonsoft.json.dll » ?
В нашей базе содержится 1611 разных файлов с именем newtonsoft.json.dll . You can also check most distributed file variants with name newtonsoft.json.dll. Чаще всего эти файлы принадлежат продукту Json.NET. Наиболее частый разработчик — компания Newtonsoft. Самое частое описание этих файлов — Json.NET .NET 2.0. Этот файл — динамически подключаемая библиотека. Такая библиотека может загружаться и выполняться любым работающим процессом.
Подробности о наиболее часто используемом файле с именем «newtonsoft.json.dll»
Продукт: Json.NET Компания: Newtonsoft Описание: Json.NET .NET 2.0 Версия: 4.5.9.15308 MD5: aa37f07c42cf858455fe32fe9c68e5c7 SHA1: 2dda873dc21db27a238be0557ddf47d4ba9f3bd7 SHA256: 2f24133eaec5e2475c24ccf813d92822be233a3e3872529a9c7296ad7fa3e823 Размер: 399280 Папка: %USERPROFILE%\AppData\Local\Facebook\Messenger\2.1.4814.0 ОС: Windows 7 Частота: Высокая Цифровая подпись: Facebook, Inc.
Проверьте свой ПК с помощью нашей бесплатной программы

System Explorer это наша бесплатная, удостоенная наград программа для быстрой проверки всех работающих процессов с помощью нашей базы данных. Эта программа поможет вам держать систему под контролем.
Библиотека «newtonsoft.json.dll» безопасная или опасная?
Последний новый вариант файла «newtonsoft.json.dll» был обнаружен 3928 дн. назад. В нашей базе содержится 120 шт. вариантов файла «newtonsoft.json.dll» с окончательной оценкой Безопасный и ноль вариантов с окончательной оценкой Опасный . Окончательные оценки основаны на комментариях, дате обнаружения, частоте инцидентов и результатах антивирусных проверок.
Библиотека с именем «newtonsoft.json.dll» может быть безопасным или опасным. Чтобы дать правильную оценку, вы должны определить больше атрибутов файла. Самый простой способ это сделать — воспользоваться нашей бесплатной утилитой для проверки файлов посредством нашей базы данных. Эта утилита содержит множество функций для контролирования вашего ПК и потребляет минимум системных ресурсов.
Щёлкните здесь, чтобы загрузить System Explorer.
Комментарии пользователей для «newtonsoft.json.dll»
У нас пока нет комментариев пользователей к файлам с именем «newtonsoft.json.dll».
Добавить комментарий для «newtonsoft.json.dll»
Для добавления комментария требуется дополнительная информация об этом файле. Если вам известны размер, контрольные суммы md5/sha1/sha256 или другие атрибуты файла, который вы хотите прокомментировать, то вы можете воспользоваться расширенным поиском на главной странице .
Если подробности о файле вам неизвестны, вы можете быстро проверить этот файл с помощью нашей бесплатной утилиты. Загрузить System Explorer.
Проверьте свой ПК с помощью нашей бесплатной программы
System Explorer это наша бесплатная, удостоенная наград программа для быстрой проверки всех работающих процессов с помощью нашей базы данных. Эта программа поможет вам держать систему под контролем. Программа действительно бесплатная, без рекламы и дополнительных включений, она доступна в виде установщика и как переносное приложение. Её рекомендуют много пользователей.
Работа с библиотекой Newtonsoft.Json на реальном примере. Часть 1
Если Вы читаете данную статью, значит, скорее всего, Вы в курсе что такое JSON и картинка ниже Вам знакома. Но в любом случае советую посетить эту страничку, если Вы там еще не были, а так же перед прочтением желательно ознакомиться с общими принципами работы с протоколом JSON на языке C#, например по этой ссылке.

Хочу отметить, что данная заметка не претендует на какую-то полноту раскрытия темы. Цель данного текста – структурировать и сохранить те наработки, которые я использовал при работе с библиотекой Newtonsoft.Json.
Постановка задачи
По большому счету, в рамках статьи не так важно каким образом были получены исходные данные, для парсинга, однако данное пояснение наверняка облегчит восприятие материала. Итак, основная задача состоит в том, чтобы реализовать функции API криптобиржи EXMO. Для простоты будем в основном работать с Публичным интерфейсом (Public API). В данном случае запрос информации будет выглядеть как обычный адрес странички сайта. Для отправки запросов используется класс WebClient пространства имен System.Net:
var wb = new WebClient(); string request = "https://api.exmo.com/v1/trades/?pair=BTC_USD"; string answer = wb.DownloadString(request);
Результат работы данной программы можно увидеть пройдя по ссылке 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 ListBTC_USD < get; set; >>
Надо отметить, что сама функция “trades” криптобиржи позволяет запрашивать информацию сразу по нескольким валютным парам. И в случае запроса
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 ListBTC_USD < get; set; >public List ETH_USD < get; set; >>
Очевидно, что для каждой комбинации валютных пар классы не подготовишь, а значит нужно как-то выкручиваться.
Как делать не нужно.
Удивительно, но хороших статей по работе с протоколом JSON в русскоязычном интернете найти практически невозможно. Как следствие, те реализации EXMO API, которые можно найти на GitHub`е так или иначе содержат манипуляции с исходной структурой данных с использованием spit`ов, trim`ов и тому подобных непотребств.
Надо признать, что я то же сначала изобрел велосипед и реализовал парсинг самостоятельно. Несмотря на то, что код абсолютно рабочий, это отличный пример как НЕЛЬЗЯ делать.
LinkedList loi = new LinkedList(); 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(); >
Объекты JSON (класс JObject)
Объект JSON — неупорядоченный набор пар ключ/значение. Объект начинается с » (закрывающей фигурной скобкой). Каждое имя сопровождается: (двоеточием), пары ключ/значение разделяются запятой.

Из структуры, предложенной нам ранее JSON C# Class Generator`ом видно, что для каждой валютной пары у нас есть 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.
Нажимаем правой кнопкой мыши на Решение (Solution) в Обозревателе решений (Solution explorer) и выбираем пункт «Управлением пакетами NuGet для решения. » («Mange NuGet Packages for solution. »).

Далее жмем «Обзор» («Browse») и в строке поиска вводим newtosoft.json. Ставим галочку напротив нашего решения и нажимаем «Установить» («Install»).
Пространство имен newtosoft.json.linq, после установки библиотеки, становится доступно для подключения к проекту:
using Newtonsoft.Json.Linq;
Для представления данных в newtosoft.json.linq используется абстрактный класс JToken, от которого наследуются классы JValue (для представления простых значений) и JContainer (для представления структур). Структуры в свою очередь могут представлять из себя JArray (массив), JConstructor (конструктор), JObject (объект), либо JProperty (свойство).
В классах JArray и JObject имеется метод Parse, позволяющей преобразовывать JSON данные из обычной строки в соответствующие объекты. Так, если мы воспользуемся методом JObject.Parse(String) для структуры данных функции trades биржи Exmo:
var wb = new WebClient(); string request = "https://api.exmo.com/v1/trades/?pair=BTC_USD,ETH_USD"; string answer = wb.DownloadString(request); JObject jObject = JObject.Parse(answer);
мы увидим структуру из двух элементов, каждый из которых представляет пару ключ-значение. Ключом в данном случае будет название валютной пары (тип String), а значением — список сделок (тип JToken):

Теперь списки сделок нам доступны по ключам «BTC_USD» и «USD_ETH». Например сделки по валютной паре «BTC_USD»:

Далее нам только останется перевести полученные данные в удобный для работы тип, например List , используя метод ToObject<>():
var wb = new WebClient(); string request = "https://api.exmo.com/v1/trades/?pair=BTC_USD,ETH_USD"; string answer = wb.DownloadString(request); JObject jObject = JObject.Parse(answer); JToken list = jObject["BTC_USD"]; List trades = list.ToObject();
либо всю структуру преобразовать в тип Dictionary> :
string request = "https://api.exmo.com/v1/trades/?pair=BTC_USD,ETH_USD"; var wb = new WebClient(); string answer = wb.DownloadString(request); JObject jObject = JObject.Parse(answer); Dictionary> trades = new Dictionary>(); foreach (KeyValuePair obj in jObject) trades.Add(obj.Key, obj.Value.ToObject>());
Массивы JSON (класс JArray)
Массив JSON — упорядоченная коллекция значений. Массив начинается с ‘[‘ (открывающей квадратной скобки) и заканчивается ‘]’ (закрывающей квадратной скобкой). Значения разделены запятой.
Как выглядит массив JSON можно увидеть пройдя по ссылке https://api.exmo.com/v1/currency. Если попытаться преобразовать его в объект JObject, так как мы делали с предыдущим запросом:
var wb = new WebClient(); string request = "https://api.exmo.com/v1/currency"; string answer = wb.DownloadString(request); JObject jObject = JObject.Parse(answer);
мы получим исключение Newtonsoft.Json.JsonReaderException, сообщающее нам, что преобразуемые данные не являются объектом.

Массивы должны быть преобразованы в специальный тип JArray, который, так же как JObject, наследуется от JContainer.
var wb = new WebClient(); string request = "https://api.exmo.com/v1/currency"; string answer = wb.DownloadString(request); JArray jArray = JArray.Parse(answer);
В случае, когда при парсинге, исходная структура заранее неизвестна, либо требуется возможность обработки обоих типов данных — в качестве типа преобразуемого объекта можно указать JContainer, или же JToken, тогда во время парсинга данные будут неявно преобразованы к нужному типу.
var wb = new WebClient(); string request = "https://api.exmo.com/v1/currency"; string answer = wb.DownloadString(request); JToken jArray = JToken.Parse(answer); // Неявное преобразование в JArray List list = jArray.ToObject(); request = "https://api.exmo.com/v1/trades/?pair=BTC_USD,ETH_USD"; answer = wb.DownloadString(request); JToken jObject = JToken.Parse(answer); // Неявное преобразование в JObject Dictionary> dict = jObject.ToObject>();
Значения JSON (класс JValue)
Согласно описанию формата JSON, значение может быть строкой в двойных кавычках, числом, true, false, null, объектом или массивом. Эти структуры могут быть вложенными. В реализации newotnsoft.json значением могут быть только объекты простых типов. Попытка преобразовать объект JArray в объект JValue приведет к исключению «System.InvalidCastException».
В качестве ознакомительного материала по работе с конкретными значениями (класс JValue) в библиотеке newtonsoft.json — хорошо подойдут примеры из документации раз и два.
Пример использования для данных с биржи:
var wb = new WebClient(); string request = "https://api.exmo.com/v1/currency"; string answer = wb.DownloadString(request); JArray jArray = JArray.Parse(answer); foreach (JValue value in jArray)
Во второй части статьи я более детально опишу возможности подготовки класса для парсинга данных, а также некоторые особенности работы с типом данных DateTime.
Полный текст программы.
using System.Collections.Generic; using System.Net; using Newtonsoft.Json; 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 < static void Main(string[] args) < var wb = new WebClient(); string request = "https://api.exmo.com/v1/currency"; string answer = wb.DownloadString(request); JToken jArray = JToken.Parse(answer); // Неявное преобразование в JArray Listlist = jArray.ToObject(); request = "https://api.exmo.com/v1/trades/?pair=BTC_USD,ETH_USD"; answer = wb.DownloadString(request); JToken jObject = JToken.Parse(answer); // Неявное преобразование в JObject Dictionary> dict = jObject.ToObject>(); > > >
Наиболее полную и подробную информацию о библиотеке всегда можно почерпнуть из официальной документации.
Работа с библиотекой Newtonsoft.Json на реальном примере. Часть 2
В первой части статьи был рассмотрен механизм парсинга объектов JSON с динамически изменяющейся структурой. Данные объекты приводились к типам пространства имен newtonsoft.json.linq, и затем преобразовывались в структуры языка C#. В комментариях к первой части было много критики, по большей части обоснованной. Во второй части я постараюсь учесть все замечания и пожелания.

Далее речь пойдет о подготовке классов для более тонкой настройки преобразования данных, но в начале необходимо вернуться к самому парсингу JSON. Напомню в первой части были использованы методы Parse() и ToObject() классов JObject и JArray пространства имен newtonsoft.json.linq:
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> dict = jObject.ToObject>();
Необходимо отметить, что в пространстве имен newtonsof.json в классе JsonConvert есть статический метод DeserializeObject<>, позволяющий преобразовывать строки напрямую в структуры C#, соответствующие объектам и массивам нотации JSON:
Dictionary> JsonObject = JsonConvert.DeserializeObject>(responseBody); List Json_Array = JsonConvert.DeserializeObject(responseBody);
И в дальнейшем в статье будет использован именно этот метод, поэтому в программу нужно добавить using newtonsoft.json.
Кроме того, есть возможность еще больше сократить количество промежуточных преобразований — после установки библиотеки Microsoft.AspNet.WebApi.Client (так же доступна через NuGet), данные можно будет парсить прямо из потока используя метод ReadAsAsync:
Dictionary> JsonObject = await (await httpClient.GetAsync(request)). EnsureSuccessStatusCode().Content. ReadAsAsync>();
За подсказку спасибо lair.
Подготовка класса для преобразования
Вернемся к нашему классу 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; >>
Напомню, он был создан на основе формата, предложенного JSON C# Class Generator`ом. Есть два момента, которые при работе с объектами данного класса могут вызвать сложности.
Первый — в таком виде свойства нашего класса нарушают правила наименования полей. Ну и кроме того, логично для объекта типа Order ожидать что его идентификатор будет называться OrderID (а не traid_id, как происходило в примерах из первой части). Чтобы связать элемент структуры JSON и свойство класса с произвольным именем, необходимо перед свойством добавить атрибут JsonProperty:
class Order < [JsonProperty("trade_id")] public int OrderID < get; set; >[JsonProperty("type")] public string Type < get; set; >[JsonProperty("quantity")] public double Quantity < get; set; >[JsonProperty("price")] public double Price < get; set; >[JsonProperty("amount")] public double Amount < get; set; >[JsonProperty("date")] public int Date < get; set; >>
В результате, значение, соответствующее элементу “trade_id”, будет записано в свойство OrderID, “type” в Type и т.д. Так же атрибут JsonProperty необходим для сериализации / десериализации свойств, имеющих модификаторы private или static — по умолчанию такие свойства игнорируются.
В итоге, код для составления списка всех OrderID сделок по валютным парам BTC_USD и ETH_USD, может выглядеть следующим образом:
using HttpClient httpClient = new HttpClient(); string request = "https://api.exmo.com/v1/trades/?pair=BTC_USD,ETH_USD"; string responseBody = await (await httpClient.GetAsync(request)). EnsureSuccessStatusCode(). Content.ReadAsStringAsync(); Dictionary> PairList = JsonConvert.DeserializeObject>(responseBody); List IDs = new List(); foreach (var pair in PairList) foreach (var order in pair.Value) IDs.Add(order.OrderID);
Вторая сложность при работе с данным классом будет заключаться в свойстве Date. Как можно увидеть, JSON C# Class Generator определил элемент “date” как простое целочисленное число. Но гораздо удобнее было бы, чтобы свойство Date нашего класса имело тип специально созданный для дат — DateTime. Как это сделать — будет описано далее.
Особенности работы с датами
Начальную фразу статьи в документации по newtonsof.json, с описанием работы с датами, можно примерно перевести как “DateTime в JSON — это тяжко”. Проблема заключается в том, что сама спецификация JSON не содержит информации о том, какой синтаксис необходимо применять для описания даты и времени.
Все относительно неплохо, когда дата в JSON строке представлена в текстовом виде и формат представления соответствует одному из трех вариантов: “Майкрософт” (в настоящее время считается устаревшим), “JavaScript” (Unix время) и вариант ISO 8601. Примеры допустимых форматов:
Dictionary d = new Dictionary < < "date", DateTime.Now >>; string isoDate = JsonConvert.SerializeObject(d); // JsonSerializerSettings microsoftDateFormatSettings = new JsonSerializerSettings < DateFormatHandling = DateFormatHandling.MicrosoftDateFormat >; string microsoftDate = JsonConvert.SerializeObject(d, microsoftDateFormatSettings); // string javascriptDate = JsonConvert.SerializeObject(d, new JavaScriptDateTimeConverter()); //
Однако в случае с биржей Exmo, все немного сложнее. В описании API биржи указано, что дата и время указываются в формате Unix (JavaScript). И, теоретически, добавив к нашему свойству Date класса Order функцию преобразования формата из класса JavaScriptDateTimeConverter(), мы должны получить дату, приведенную к типу DateTime:
class Order < [JsonProperty("trade_id")] public int OrderID < get; set; >[JsonProperty("type")] public string Type < get; set; >[JsonProperty("quantity")] public double Quantity < get; set; >[JsonProperty("price")] public double Price < get; set; >[JsonProperty("amount")] public double Amount < get; set; >[JsonProperty("date", ItemConverterType = typeof(JavaScriptDateTimeConverter))] public DateTime Date < get; set; >>
Однако в этом случае, при попытке парсинга данных в переменную типа DateTime появляется уже знакомое по первой части статьи исключение Newtonsoft.Json.JsonReaderException. Происходит это по причине того, что функция преобразования класса JavaScriptDateTimeConverter не умеет конвертировать числовые данные в тип DateTime (это работает только для строк).

Возможный выход из данной ситуации — написать свой собственный класс преобразования форматов. На самом деле такой класс уже есть и его можно использовать, предварительно подключив пространство имен Newtonsoft.Json.Converters (обратите внимание, что обратная функция — конвертирования из DateTime в формат JSON в данном классе не реализована):
class UnixTimeToDatetimeConverter : DateTimeConverterBase < private static readonly DateTime _epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) < throw new NotImplementedException(); >public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) < if (reader.Value == null) < return null; >return _epoch.AddSeconds(Convert.ToDouble(reader.Value)).ToLocalTime(); > >
Остается только подключить нашу функцию к свойству Date класса Order. Для этого необходимо использовать атрибут JsonConverter:
class Order < [JsonProperty("trade_id")] public int OrderID < get; set; >[JsonProperty("type")] public string Type < get; set; >[JsonProperty("quantity")] public double Quantity < get; set; >[JsonProperty("price")] public double Price < get; set; >[JsonProperty("amount")] public double Amount < get; set; >[JsonProperty("date")] [JsonConverter(typeof(UnixTimeToDatetimeConverter))] public DateTime Date < get; set; >>
Теперь наше свойство Date имеет тип DateTime и мы можем, например, сформировать список сделок, за последние 10 минут:
HttpClient httpClient = new HttpClient(); string request = "https://api.exmo.com/v1/trades/?pair=BTC_USD,ETH_USD"; string responseBody = await (await httpClient.GetAsync(request)). EnsureSuccessStatusCode(). Content.ReadAsStringAsync(); Dictionary> PairList = JsonConvert.DeserializeObject>(responseBody); List Last10minuts = new List(); foreach (var pair in PairList) foreach (var order in pair.Value) if (order.Date > DateTime.Now.AddMinutes(-10)) Last10minuts.Add(order);
Полный текст программы
using System; using System.Threading.Tasks; using System.Collections.Generic; using System.Net.Http; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Serialization; namespace JSONObjects < class Order < [JsonProperty("pair")] public string Pair < get; set; >[JsonProperty("trade_id")] public int OrderID < get; set; >[JsonProperty("type")] public string Type < get; set; >[JsonProperty("quantity")] public double Quantity < get; set; >[JsonProperty("price")] public double Price < get; set; >[JsonProperty("amount")] public double Amount < get; set; >[JsonProperty("date")] [JsonConverter(typeof(UnixTimeToDatetimeConverter))] public DateTime Date < get; set; >> class UnixTimeToDatetimeConverter : DateTimeConverterBase < private static readonly DateTime _epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) < throw new NotImplementedException(); >public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) < if (reader.Value == null) < return null; >return _epoch.AddSeconds(Convert.ToDouble(reader.Value)).ToLocalTime(); > > class Program < public static async Task Main(string[] args) < using HttpClient httpClient = new HttpClient(); string request = "https://api.exmo.com/v1/trades/?pair=BTC_USD,ETH_USD"; string responseBody = await (await httpClient.GetAsync(request)). EnsureSuccessStatusCode(). Content.ReadAsStringAsync(); Dictionary> PairList = JsonConvert. DeserializeObject>(responseBody); List Last10minuts = new List(); foreach (var pair in PairList) foreach (var order in pair.Value) if (order.Date > DateTime.Now.AddMinutes(-10)) Last10minuts.Add(order); > > >
Подмена имен элементов JSON
Ранее мы работали с командой trades биржи. Данная команда возвращает объекты со следующими полями:
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; >>
Команда биржи user_open_orders возвращает очень похожую структуру:
public class BTCUSD < public string order_id < get; set; >public string created < get; set; >public string type < get; set; >public string pair < get; set; >public string quantity < get; set; >public string price < get; set; >public string amount < get; set; >>
Поэтому имеет смысл адаптировать класс Order, чтобы в него можно было преобразовывать не только данные команды trade, но также и данные команды user_open_orders.
Отличия заключаются в том, что появился новый элемент pair, содержащий название валютной пары, trade_id заменен на order_id (и теперь это строка), а date стала created и тоже является строкой.
Начнем с того, что добавим возможность сохранения полей order_id и created в соответствующие поля OrderID и Date класса Order. Для этого подготовим класс OrderDataContractResolver, в котором будет происходить подмена имен полей для парсинга (потребуются пространства имен System.Reflection и Newtonsoft.Json.Serialization):
class OrderDataContractResolver : DefaultContractResolver < public static readonly OrderDataContractResolver Instance = new OrderDataContractResolver(); protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) < var property = base.CreateProperty(member, memberSerialization); if (property.DeclaringType == typeof(Order)) < if (property.PropertyName.Equals("trade_id", StringComparison.OrdinalIgnoreCase)) < property.PropertyName = "order_id"; >if (property.PropertyName.Equals("date", StringComparison.OrdinalIgnoreCase)) < property.PropertyName = "created"; >> return property; > >
Далее этот класс необходимо указать в качестве параметра метода DeserializeObject следующим образом:
Dictionary> PairList = JsonConvert.DeserializeObject>(responseBody, new JsonSerializerSettings < ContractResolver = OrderDataContractResolver.Instance >);
В результате, такая JSON структура, полученная в качестве ответа на команду user_open_orders:
будет преобразована в такую структуру данных:

Обратите внимание, что для корректной работы программы, тип поля OrderID в классе Order пришлось заменить на string.
Полный текст программы
using System; using System.Threading.Tasks; using System.Collections.Generic; using System.Net.Http; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Serialization; using System.Reflection; namespace JSONObjects < class Order < [JsonProperty("pair")] public string Pair < get; set; >[JsonProperty("trade_id")] public string OrderID < get; set; >[JsonProperty("type")] public string Type < get; set; >[JsonProperty("quantity")] public double Quantity < get; set; >[JsonProperty("price")] public double Price < get; set; >[JsonProperty("amount")] public double Amount < get; set; >[JsonProperty("date")] [JsonConverter(typeof(UnixTimeToDatetimeConverter))] public DateTime Date < get; set; >> class OrderDataContractResolver : DefaultContractResolver < public static readonly OrderDataContractResolver Instance = new OrderDataContractResolver(); protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) < var property = base.CreateProperty(member, memberSerialization); if (property.DeclaringType == typeof(Order)) < if (property.PropertyName.Equals("trade_id", StringComparison.OrdinalIgnoreCase)) < property.PropertyName = "order_id"; >if (property.PropertyName.Equals("date", StringComparison.OrdinalIgnoreCase)) < property.PropertyName = "created"; >> return property; > > class UnixTimeToDatetimeConverter : DateTimeConverterBase < private static readonly DateTime _epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) < throw new NotImplementedException(); >public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) < if (reader.Value == null) < return null; >return _epoch.AddSeconds(Convert.ToDouble(reader.Value)).ToLocalTime(); > > class Program < public static async Task Main(string[] args) < using HttpClient httpClient = new HttpClient(); string request = "https://api.exmo.com/v1/trades/?pair=BTC_USD,ETH_USD"; string responseBody = await (await httpClient.GetAsync(request)). EnsureSuccessStatusCode(). Content.ReadAsStringAsync(); Dictionary> PairList = new Dictionary>(); JObject jObject = JObject.Parse(responseBody); foreach (var pair in jObject) < Listorders = new List(); foreach (var order in pair.Value.ToObject()) < order.Pair = pair.Key; orders.Add(order); >PairList.Add(pair.Key, orders); > responseBody = "<\"BTC_USD\":[<\"order_id\":\"4722868563\"," + "\"created\":\"1577349229\",\"type\":\"sell\"," + "\"pair\":\"BTC_USD\",\"quantity\":\"0.002\"," + "\"price\":\"8362.2\",\"amount\":\"16.7244\">]>"; Dictionary> PairList1 = JsonConvert.DeserializeObject> (responseBody, new JsonSerializerSettings < ContractResolver = OrderDataContractResolver.Instance >); > > > >
Как можно заметить, при вызове команды user_open_orders, ответ содежит поле “pair”, в случае же команды trade информация о валютной паре содержится только в значении ключа. Поэтому придется либо заполнить поле Pair уже после парсинга:
foreach (var pair in PairList) foreach (var order in pair.Value) order.Pair = pair.Key;
Либо же воспользоваться объектом JObject:
Dictionary> PairList = new Dictionary>(); JObject jObject = JObject.Parse(responseBody); foreach (var pair in jObject) < Listorders = new List(); foreach (var order in pair.Value.ToObject()) < order.Pair = pair.Key; orders.Add(order); >PairList.Add(pair.Key, orders); >
Что в конечном итоге приведет к созданию следующей структуры данных: