Как стать автором
Обновить

Комментарии 41

А зачем вам промежуточный JObject, если можно прекрасно десериализовывать сразу в нужный тип? Не говоря уже о том, что не надо считывать ответ в строку, можно делать десериализацию из потока, да и WebClient тоже использовать не нужно?


Проще говоря, весь нужный код сводится к


await (await httpClient.GetAsync(uri)).EnsureSuccessStatusCode().Content.ReadAsAsync<T>();
JObject, также как и промежуточные строки мне нужны для понимания происходящего. Как уже справедливо было замечено в комментариях — я пока далек от .Net, да и от программирования в целом. Но у меня есть цель с ними сблизиться или даже породниться. Мне сейчас очень не хватает подобных статей, где, возможно, с точки зрения языка все не очень красиво, но зато абсолютно понятно. Мне потребовалось несколько часов чтобы осознать и воспроизвести Вашу строчку кода. И я, с Вашего позволения, использую ее во второй части статьи, но не здесь.
Я заменил webClient на httpClient, в остальном же я, пожалуй, оставлю все как есть.

Если вам требуется JObject "для понимания происходящего" — значит у вас неправильное понимание происходящего...

Это не так.

Скажите, вы думаете, что при десериализации объекта из потока (через JsonSerializer.Deserialize) где-то фигурирует JObject?

Нет, я не думаю, что при десериализации через JsonSerializer.Deserialize происходит формирование промежуточных объектов. Насколько я понимаю, они нужны для сериализации и мое их использование не совсем по назначению.

И для сериализации они тоже вовсе не обязательны.

А для чего они обязательны?

Они нужны для работы с нетипизированными данными.

Ни для чего. С ними удобнее разбирать не- и слабо-типизованные данные, но даже это можно делать без них.

Насколько я понимаю, они нужны для сериализации

Нет, не нужны.


мое их использование не совсем по назначению.

Именно. Что возвращает нас к идее о том, что понимать происходящее через JObject, который нигде для этого "происходящего" не используется — странно.

Возможно. Если Вы сможете предложить что-нибудь более подходящее для объяснения что такое объект, массив и значение JSON — буду признателен.

Спецификация JSON, очевидно.


Но вообще, эти понятия имеют вполне прямые соответствия в .net — словарь, массив и примитивное значение.

Для меня было совсем не очевидно как сопоставить набор символов, который представляет из себя объект JSON и соответствующие им конструкции .Net.

Так и сопоставить: вот такая запись эквивалентна вот такой конструкции, вот такая — вот такой. Промежуточные конструкции Newtonsoft.Json.Linq здесь лишние.

Что такое 2 + 2? Это когда берем 2 яблока и добавляем еще 2 яблока. Да, яблоки тут лишние, но так понятней.
JObject, также как и промежуточные строки мне нужны для понимания происходящего.

Так вы определитесь, ваша статья — она про работу с библиотекой или про то, как вы понимаете происходящее? Потому что работать с этой библиотекой так, как вы показываете, не надо.

Зачем вообще писать:

Никогда не угадаешь, кто прочитает ваш пост. Часто это те, кто разбирается в вопросе на голову лучше вас. Фидбэк от таких людей — возможно, самое ценное, что вы приобретете на Хабре.

Мой вопрос не в том, что вы приобретаете от этого поста. Мой вопрос в том, что аудитория хабра от него приобретает.

Я уже написал, что мне не хватало именно такой статьи. И я верю, что я такой не один. Возможно, делать так, как описано в статье и не нужно но это работает, а значит может быть где-то полезно.
но это работает, а значит может быть где-то полезно.

Это глубоко ошибочное мнение. Не все, что "работает", может быть полезно — до тех пор, пока вы не понимаете весьма конкретно, что именно "работает" и как.

Не мой взгляд, главной рекомендацией является отказ от WebClient и Newtonsoft.Json в сторону HttpClient и System.Text.Json/Utf8JsonSerializer

Вместо DTO можно использовать dynamic:


string json = "{\"name\": \"Johny\"}";
dynamic obj = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(json);
Console.WriteLine($"Name = {obj.name}");

А зачем?

Сходил по ссылкам и хотел, было, написать, что ещё 4 года назад API этого сайтика был кем-то реализован на C# и притом уже с HttpClient и async'ами, но потом посмотрел в тот код и… Пожалуй, лучше похвалить автора этой статьи за попытку. Довольно наивную (выглядит, будто сильно далёкий от .net человек попытался что-то написать по статьям десятилетней давности), но зато честно самостоятельную.
По сути:


  1. async/await нужен. уже даже public static async Task Main(string[] args) можно
  2. WebClient забыть в пользу HttpClient (по большей части из-за п1, впрочем).
  3. Промежуточные JObject для парсинга в объект не нужны. Его назначение как раз наоборот — не собирая конечную модель работать просто с json-деревом. Дада, тот самый JsonConvert.DeserializeObject<>(), на который уже выше указали
  4. JSON — не протокол. Это разметка, нотация, формат если хочешь.
  5. Ну и да, System.Text.Json ещё далековат от полноценной продакш-реди замены newtonsoft'у, но всё ж для таких простых вещей можно и на него посмотреть (кстати, есть ещё и JsonReader — тоже классная штука).
Спасибо, добрый человек, за науку. WebClient обязательно переделаю на HttpClient и добавлю async/await.
Что же касается промежуточных string, JObject и т.д., то они были нужны мне для понимания внутренних процессов. Все же статья не о том, как написать максимально компактный код.
JsonConvert.DeserializeObject<>() будет во второй части.
В дополнение к прочим комментариям добавлю, что ресурсы нужно освобождать.
В вашем случае, это объект WebClient, т.е. нужно было обернуть его создание в конструкцию using или (для последних версий C#) написать

using var wb = new WebClient();


В общем, статья больше похожа на вредный совет, как писать не нужно.
А HttpClient не нужно. Лучше его статиком сделать. У Microsoft просто очень логичное API :)

Вообще-то нужно, если только вы не собираетесь ограничивать количество одновременных запросов до одного.

Тогда стоит использовать фабрику, но ни в коем случае не обычный диспозабельный HttpClient, иначе у вас будут утекать ресурсы, с весьма неприятными последствиями. Если что, в Microsoft после нескольких пинков поправили документацию, так что там теперь это указано.

А можно подробнее про утечку ресурсов? Откуда они вообще возьмутся, чтобы утекать?

В документации как бы расписано теперь
HttpClient is intended to be instantiated once and re-used throughout the life of an application. Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads.


Ну и про один запрос оттуда же
The HttpClient class instance acts as a session to send HTTP requests. An HttpClient instance is a collection of settings applied to all requests executed by that instance. In addition, every HttpClient instance uses its own connection pool, isolating its requests from requests executed by other HttpClient instances.


В реальности, мне писали, что получали SocketException, у нас было веселее — приложение чем дольше работало, тем больше процессора использовало. Т.е. после пары недель работы 100%. А при подключении к нему отладчика — всё сбрасывалось и опять типа норма. Приятного анализа, блин.

Да, и работает это именно под Core 2.2 и выше. В более старых версиях — используется другая реализация, а в большом .NET — тот же HttpWebRequest, который не страдает этой проблемой.
Еще подробная статья была на хабре: habr.com/ru/post/424873

Да, я её читал, но именно утечки ресурсов я там не увидел, только длинные TIME_WAIT.

Там автор больше напирает на .NET Framework и Windows, там утечки нет, потому что под капотом у HttpClient находится банальный HttpWebRequest, со своими тараканами, но без утечек. Утечки именно появились в .NET Core 2.2, где сделали свою реализацию работы с HTTP (быстрее, выше, сильнее). Поэтому многие очень удивились проблемам, когда просто обновили фреймворк, не меняя ни строчки в приложении и получили подобное поведение.
Очень прошу вас использовать в названиях соглашения по именам для C#. Для публичных свойств класса это PascalCase.
Для биндинга свойств удобно использовать [JsonProperty(PropertyName = «jsonBindingName»)]
Про это будет рассказано во второй части.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории