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

Получить неполучаемое или «Как я писал свой велосипед для VK.NET API в 21-м веке»

Приветствую, коллеги. Сегодня речь пойдёт о том, как я столкнулся с весьма неприятным косяком библиотеки VK.NET для работы с VK API в программах на базе C# (.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.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.