Зависает Telegram бот на обработке CallbackQuery

Создаю сообщение с InlineKeyboardButton.WithCallbackData. Далее надо обработать нажатие на кнопку и обработку. Сейчас код просто выводит выбранный результат. Сама проблема заключается в том, что при нажатии на эту кнопку бот просто зависает и не реагирует ни на что, до тех пор пока его не перезапустишь.

Самой обработки тоже не проиходит. Ничего никуда не выводиться, а просто часть с case UpdateType.CallbackQuery: просто пропускается. Ошибок никаких не выдает, просто намертво зависает для этого пользователя.

private void startBtn_Click(object sender, EventArgs e)
        {
            cts = new CancellationTokenSource();
            botClient.StartReceiving(Update, Error, cancellationToken: cts.Token);
        }

private async Task Update(ITelegramBotClient client, Update update, CancellationToken c_token)
        {
            var message = update.Message;
            logsListBox.Items.Add($"{message.Date}, {message.Chat.Id}: {message.Text}");
            switch (update.Type)
            {
                case UpdateType.Message:
                    if (message.Text == "/start")
                    {
                        _ = await botClient.SendTextMessageAsync(
                            chatId: message.Chat.Id,
                            text: "Trying *all the parameters* of `sendMessage` method",
                            parseMode: ParseMode.MarkdownV2,
                            disableNotification: false,
                            replyToMessageId: message.MessageId,
                            replyMarkup: new InlineKeyboardMarkup(new[]
                            {
                                InlineKeyboardButton.WithCallbackData("EN", "en"),
                                InlineKeyboardButton.WithCallbackData("DE", "de"),
                            }),
                            cancellationToken: c_token);
                    };
                    break;

                case UpdateType.CallbackQuery:
                    var pressedButtonID = update.CallbackQuery.Data;
                    logsListBox.Items.Add($"{pressedButtonID}");
                    _ = await botClient.SendTextMessageAsync(
                            chatId: message.Chat.Id,
                            text: pressedButtonID,
                            parseMode: ParseMode.MarkdownV2,
                            cancellationToken: c_token);
                    break;

                default:
                    break;
            }
        }

Пример работы бота Вот пример работы. Все работало и реагировало, до тех пор пока не нажал на кнопку "EN", после этого программа даже не видит новых сообщений.


Ответы (1 шт):

Автор решения: aepot

С UI элементами надо работать в UI потоке.

Например так.

this.Invoke(() => logsListBox.Items.Add($"{pressedButtonID}"));

А еще лучше заведите метод

private void Log(string message)
{
    Action action = () => logsListBox.Items.Add(message);
    if (this.InvokeRequired)
        this.Invoke(action);
    else
        action();
}

И теперь можно не думая о потоках писать Log($"{pressedButtonID}");


Есть кросс-платформенный метод сделать то же самое с помощью класса Progress<T>. Предыдущий будет работать только в WinForms.

Просто заведите поле

private readonly IProgress<string> log;

В конструкторе формы допишите после InitializeComponent();

log = new Progress<string>(m => logsListBox.Items.Add(m));

Этот конструктор захватит контекст синхронизации при создании экземпляра.

Теперь можно писать так: log.Report($"{pressedButtonID}"); всё так же из любого потока.

Не забудьте применить выбранный подход для всех вызовов из сторонних потоков, а не только в одном месте, с листбоксом нельзя работать из стороннего потока вообще. Именно по этой причине вы могли нарваться на рассинхрон и дедлок (зависание).


Также возможно вы не обрабатываете ошибки в Error. Покажите обработчик, дополню ответ, если с ним что-то не так.


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

_ = Task.Run(() => botClient.StartReceiving(Update, Error, cancellationToken: cts.Token));
→ Ссылка