Получить неполучаемое или «Как я писал свой велосипед для VK.NET API в 21-м веке»
Ожидает приглашения
Приветствую, коллеги. Сегодня речь пойдёт о том, как я столкнулся с весьма неприятным косяком библиотеки VK.NET для работы с VK API в программах на базе C# (.NET), а именно — с багом возврата коллекции репостов.
На днях получил заказ разработать автолайкер репостов в пабликах сервиса VK.COM. И всё было хорошо, пока дело не дошло до самого метода получения списка репостов:
Далее расскажу вкратце с чем пришлось столкнуться и как я проблему сею обошёл.
Самым забавным было то, что как бы я не пытался передавать аргументы в данный метод, я постоянно ловил исключение ArgumentNullException, если загнать аргументы явными литералами переменных (да хоть констант, ему до лампочки, как выяснилось), метод возвращает null. Такое впечатление, что разработчики VkNet просто недопилили этот метод, либо что-то пропустили. Как же быть в такой ситуации?
Решение, ясное дело, не заставило себя долго ждать, я вызвал явно метод VK API wall.getReposts():
Дальше просто парсим ответ из JSON в объект .NET и получаем список репостов. Profit? А вот и нет… Всё не так просто, как хотелось бы, в процессе тестирования выяснилось, что VK API каким-то непонятным моей логике образом отдаёт за раз пачку репостов по 2-4 штуки, не более, что не есть гуд вообще. И какие бы я ему параметры offset и count не задавал — в ответ получаю одну и ту же картину. Причём, на одних записях может вернуть всю пачку репостов, на других — только часть, на третьих — вообще ничего, хотя по факту там может быть сколько угодно репостов. Самое странное, что в песочнице VK API всё работает как нужно (баг VkNet?). Как быть?
Итак, узнаём сперва сколько всего репостов у записи (хватит обычного Post.Reposts.Count), после чего циклом делаем Invoke до тех пор, пока не вытащим все пачки репостов, не забывая менять offset на каждой итерации:
Лишь после этого мне удалось вытянуть все репосты у записи.
Вот такая маленькая «костыльная» история у меня произошла на днях. В процессе довелось столкнуться ещё с парой не очень приятных моментов (например, ни в какую не хотели парситься типы VkNet.Enums из JSON, из-за чего мне пришлось писать пару собственных структур данных для хранения ответной выборки из Invoke), но там скорее всего уже я чего-то недопонял, ибо времени на ковыряние исходников VkNet было катастрофически мало, нужно было в темпе закрывать проект.
Документация по методу Wall.GetResponse() из VK.NET.
С чего всё началось
На днях получил заказ разработать автолайкер репостов в пабликах сервиса VK.COM. И всё было хорошо, пока дело не дошло до самого метода получения списка репостов:
public WallGetObject GetReposts(long? ownerId, long? postId, long? offset, long? count);
Далее расскажу вкратце с чем пришлось столкнуться и как я проблему сею обошёл.
Что не так с Wall.GetReposts()?
Самым забавным было то, что как бы я не пытался передавать аргументы в данный метод, я постоянно ловил исключение ArgumentNullException, если загнать аргументы явными литералами переменных (да хоть констант, ему до лампочки, как выяснилось), метод возвращает null. Такое впечатление, что разработчики VkNet просто недопилили этот метод, либо что-то пропустили. Как же быть в такой ситуации?
Обращаемся к низкоуровневому API.Invoke() VK API
Решение, ясное дело, не заставило себя долго ждать, я вызвал явно метод VK API wall.getReposts():
string response = api.Invoke("wall.getReposts", new Dictionary<string, string>()
{
["owner_id"] = post.OwnerId.Value.ToString(),
["post_id"] = post.Id.Value.ToString(),
["offset"] = "0",
["count"] = "1000",
});
Дальше просто парсим ответ из JSON в объект .NET и получаем список репостов. Profit? А вот и нет… Всё не так просто, как хотелось бы, в процессе тестирования выяснилось, что VK API каким-то непонятным моей логике образом отдаёт за раз пачку репостов по 2-4 штуки, не более, что не есть гуд вообще. И какие бы я ему параметры offset и count не задавал — в ответ получаю одну и ту же картину. Причём, на одних записях может вернуть всю пачку репостов, на других — только часть, на третьих — вообще ничего, хотя по факту там может быть сколько угодно репостов. Самое странное, что в песочнице VK API всё работает как нужно (баг VkNet?). Как быть?
Решение — смещение в цикле запроса
Итак, узнаём сперва сколько всего репостов у записи (хватит обычного Post.Reposts.Count), после чего циклом делаем Invoke до тех пор, пока не вытащим все пачки репостов, не забывая менять offset на каждой итерации:
do
{
string response = api.Invoke("wall.getReposts", new Dictionary<string, string>()
{
["owner_id"] = post.OwnerId.Value.ToString(),
["post_id"] = post.Id.Value.ToString(),
["offset"] = reposts.Count.ToString(),
["count"] = "1000",
});
// TODO: Добавить Range спарсенных объектов репостов.
}
while (reposts.Count < post.Reposts.Count);
Лишь после этого мне удалось вытянуть все репосты у записи.
Послесловие
Вот такая маленькая «костыльная» история у меня произошла на днях. В процессе довелось столкнуться ещё с парой не очень приятных моментов (например, ни в какую не хотели парситься типы VkNet.Enums из JSON, из-за чего мне пришлось писать пару собственных структур данных для хранения ответной выборки из Invoke), но там скорее всего уже я чего-то недопонял, ибо времени на ковыряние исходников VkNet было катастрофически мало, нужно было в темпе закрывать проект.
Ссылки по теме
Документация по методу Wall.GetResponse() из VK.NET.