Пишем бота telegram на C#

Вступление

Как я и обещал — пишу вторую статью по созданию ботов к известному мессенджеру telegram. В этот раз речь пойдет о языке C# и о создании полноценного бота на нем. И так, начнем, пожалуй.

Шаг первый. Создаем оформление бота через Botfather

В этот шаг я скопировал часть статьи из бота на php, так как тут все действия у нас будут полностью идентичны.

BotFather — это такой бот(официальный), через которого регистрируют все остальные боты. Без него нам никак не обойтись, поэтому давайте откроем telegram и перейдем по ссылке — BotFather

Там все крайне просто, вбиваем /help и смотрим на список доступных команд:

Собственно сейчас нас интересует команда /newbot, пишем ее и создаем бота указывая его название. В данном случае я назову своего бота — Рев.ком.стих и будет он у нас выдавать стихи о Маяковского и Есенина (когда я его доделаю, однако весь процесс в эту статью я включать не буду).

Нам выдадут токен, на скриншоте он замазан в целях…, ну вы сами понимаете. Этот токен нам и нужен, сохраните его куда-нибудь в текстовый файл, он нам еще пригодится.

 

Далее можно задать оформление для бота. Например картинку — логотип. Для этого используем команду /setuserpic после чего загружаем картинку. Так-же задаются описание бота и прочие вещи до которых вы допрете и без моего участия.

Ну и чтобы проверить установилась картинка или нет переходим на бота вбивая его имя через собачку в поиск

Теперь надо сделать боту доступ к сообщениям пользователей, то есть выключить нахер приватный режим. Если мы планируем добавлять бота в группы или конфы, назовите как хотите, в любом случае приватность нам нахер не нужна. Чтобы ее выключить вбиваем команду /setprivacy после чего выбираем пункт — disabled. Обязательно выполните этот шаг, если вы хотите сделать действительно интерактивного бота.

Теперь самое время заняться backend частью, а именно написанием кода для команд нашего бота, но сначала настроим среду разработки.

Шаг второй. Среда разрабтки

В случае с c# мы будем использовать кроссплатформенную и совершенно бесплатную ide — SharpDevelop в которую уже предустановлены все необходимые для нас плагины такие как nuget package manager. Это во первых экономит мне время, во вторых ресурсы. Тяжелая visual studio тащит за собой кучу уже давно неакутальных и ненужных вещей, да к тому-же платная. Выглядит она конечно приятнее, но для меня такие мелочи не самое главное, мне главное — результат (это нифига не мелочи, Visual Studio 2017 стоит 37 000 рублей).

Короче если у вас не стоит — установите, она весит не много. К тому-же проекты написанные в ней целиком совместимы с visual studio, то есть написанное можно будет потом перенести и туда тоже.

Создаем File->New->Solution

 

И выбираем тип, так как писать мы будем на C# то выбор очевиден:

 

И вот среда для разработки у нас готова:

Собственно время устанавливать нужные нам компоненты.

Шаг третий. Установка компонент

В качестве обертки для работы с API мы будем использовать пакет под названием telegram.bot, его мы и будем устанавливать в наш проект. Идем в Project->Manage Packages

 

Перед нами появится менджер пакетов, который сам найдет нужный нам пакет из интернета, скачает его и установит в ваше приложение для использования. Ищем там наш компонент и тыкаем «Add»:

И вот наш пакет добавился, его видно в solution explorer’е

Отлично, если вы проделали все эти действия то можно переходить уже и к кодингу.

Шаг третий. Написание кода

Собственно для начала сделаем простейший интерфейс. Переключаемся на вкладку MainForm -> Design, после чего кидаем на форму одну кнопку и одно текстовое поле.

Вообще я рассчитываю что у вас есть некий базовый опыт программирования на C#, потому что полностью описывать тут все действия у меня просто не хватит места. В любом случае после оформления стоит перейти к написанию кода.

Для начала стоит вспомнить о главном преимуществе C# — асинхронности. Я буду писать код в двух потоках и в качестве второго потока буду использовать класс BackgroundWorker. Просто создаем переменную этого класса и среда сама предложит нам установить необходимые зависимости.

Да, это еще одна вещ за которую я просто обожаю C#. Мне достаточно знать имя класса, а где он находится система знает и без меня.

Далее добавляем инициализацию нашей переменной в конструкторе класса, а так-же запилим запуск воркера по клику кнопочки.

                BackgroundWorker bw;
		
		public MainForm(){
			//
			// The InitializeComponent() call is required for Windows Forms designer support.
			//
			InitializeComponent();
			
			//
			// TODO: Add constructor code after the InitializeComponent() call.
			//
			
			this.bw = new BackgroundWorker();
			this.bw.DoWork += this.bw_DoWork; // метод bw_DoWork будет работать асинхронно
		}

		void bw_DoWork(object sender, DoWorkEventArgs e)
		{
			var worker = sender as BackgroundWorker; // получаем ссылку на класс вызвавший событие
			
		}
		
		void BtnRunClick(object sender, EventArgs e) // обработка клика кнопки
		{
		    if (this.bw.IsBusy != true) // если не запущен
		    {
		        this.bw.RunWorkerAsync(); // запускаем
		    }
		}

вот примерно так и должно быть у вас в начале. Теперь нам надо передать токен из текстового поля формы в обработчик воркера и там использовать. Звучит конечно писец как сложно но делается очень просто:

		void bw_DoWork(object sender, DoWorkEventArgs e)
		{
			var worker = sender as BackgroundWorker;
			var key = e.Argument as String; // получаем ключ из аргументов
			
			
		}
		
		void BtnRunClick(object sender, EventArgs e)
		{
			var text = txtKey.Text; // получаем содержимое текстового поля txtKey в переменную text
			if (text && this.bw.IsBusy != true)
		    {
		        this.bw.RunWorkerAsync(text); // передаем эту переменную в виде аргумента методу bw_DoWork
		    }
		}
	}

Вообще тот кто кодил на C# по больше моего конечно смог бы реализовать это все элегантнее, наверное, но я не из таких. К тому-же далеко не всем известны примочки многопоточности встроенные в этот язык. Там еще есть классы Thread и ThreadPool, а еще полу-асинхронные async и await.

Теперь настало время получения данных из бота. То есть время работы с API телеграма. Собственно инициализация API выглядит так:

var Bot = new Telegram.Bot.Api(key);

Так как мы не используем WebHook то … будем получать обновления бота «вручную», я не знаю как это можно более корректно назвать. Короче раз в секунду телеграм предоставляет ботам информацию о всех сообщениях, которые за это время поступили в бота. Эту информацию можно получать автоматически на https домен, так мы делали на php, а можно получать в бесконечном цикле внутри потока, что мы сейчас и собираемся сделать. Поток у нас есть, осталось сделать цикл и получать обновления. Собственно последнее выполняется вызовом Bot.GetUpdatesAsync(offset) который возврщает массив обновлений начиная с отступа «offset».

	async void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            var worker = sender as BackgroundWorker;
            var key = e.Argument as String; // получаем ключ из аргументов
            try
            {
                var Bot = new Telegram.Bot.TelegramBotClient(key); // инициализируем API
                await Bot.SetWebhookAsync("");
                //Bot.SetWebhook(""); // Обязательно! убираем старую привязку к вебхуку для бота
                int offset = 0; // отступ по сообщениям
                while (true)
                {
                    var updates = await Bot.GetUpdatesAsync(offset); // получаем массив обновлений
                    
                    foreach(var update in updates) // Перебираем все обновления
                    {
                        Console.WriteLine(update.Type);
                        offset = update.Id + 1;
                    }

                }
            }
            catch (Telegram.Bot.Exceptions.ApiRequestException ex)
            {
                Console.WriteLine(ex.Message); // если ключ не подошел - пишем об этом в консоль отладки
            }

        }

И так, в цикле мы перебираем обновления, теперь надо взять обновления нужного нам типа, получить их содержимое и обработать. В данном случае давайте обработаем команду «/saysomething», для этого нам надо отловить обновление типа текстовое сообщение и если текст этого сообщения совпадает с «/saysomething» значит выдать в ответ в тот-же чат строчку «тест».

foreach(var update in updates) // Перебираем все обновления
{
	var message = update.Message;
	if (message.Type == Telegram.Bot.Types.Enums.MessageType.TextMessage)
	{
		if (message.Text == "/saysomething")
		{
			// в ответ на команду /saysomething выводим сообщение
			await Bot.SendTextMessage(message.Chat.Id, "тест",
				   replyToMessageId: message.MessageId);
		}
	}
	offset = update.Id + 1;
}

Запустим теперь наше приложение, вставим токен и нажмем кнопку «поехали».

Отлично, а теперь в телеграм-боте вобьем нашу команду и посмотрим придет ли ответ:

Наш бот работает. Без регистрации домена, указания SSL, подключения cloudflare и прочих муторных вещей.

Отправка картинок

Чтобы отправить картинку надо отправить ссылку на нее самому telegram’у, он сам все загрузит и сделает за нас. Заставим нашего бота по команде «/getimage» отсылать нам вот эту картинку.

if (message.Text == "/getimage")
{
	// в ответ на команду /getimage выводим картинку
	await Bot.SendPhotoAsync(message.Chat.Id, "http://aftamat4ik.ru/wp-content/uploads/2017/03/photo_2016-12-13_23-21-07.jpg","Revolution!");
}

Запускаем, тыкаем кнопочку  и тестируем:

С отправкой документов я не буду мучиться потому что тут придется писать OpenFileDialog и прочие вещи описывать на которые тут просто не хватит места, статья и без того длинная.

Задаем список команд

Как это сделать я уже писал и не вижу ни малейшего смысла писать это снова. Просто прочитайте тут.

Заключение

Как вы уже поняли данный способ создания бота позволяет вам обойтись без покупки сервера, домена и прочих вещей, так как вы можете разместить бота прямиком на своем собственном ноутбуте/компьютере. Причем без велосипедов вроде денвера или опен-сервера.

То-же самое можно написать и на nodejs, к примеру.

Надеюсь эта статья поможет вам.

Скачать исходники

Без исходников все мои слова были бы бесполезны. Как говорится можно десять раз прочитать и не понять, а можно один раз посмотреть код и все понять. Да, к стати, проект открывается в visual studio, я проверял.

Бот для Telegram на C#
Скачано: 74, размер: 4.5 MB, дата: 28.Мар.2017

Запись Пишем бота telegram на C# впервые появилась Личный блог Гарри.

Источник

Комментарии (9):

seoonly.ru19.06.2017 02:52

Продолжаете радовать-)

aftamat4ik19.06.2017 02:52

еще бы) заглядывайте

Илья19.06.2017 02:52

всё очень круто, но я не понял как убрать старую привязку к вебхуку, можешь пояснить??

aftamat4ik19.06.2017 02:52

в код посмотрите внимательно, там это есть
ну или ладно вот скопирую для вас

Bot.SetWebhook(""); // Обязательно! убираем старую привязку к вебхуку для бота
Сергей19.06.2017 02:52

спасибо!
отличное начало для ботостроения на шарпе

нахера19.06.2017 02:52

нахера ты пишешь нахера? это так уёбищно выглядит. И это, ты даун или прикидываешься, писать что студия стоит 37 кусков?
Блять с 2015 студии есть community edition которая такая же как про, только бесплатная для простых ребят. И текст прогняй через word, потому что очень много ошибок, читать ужасно.

aftamat4ik19.06.2017 02:52

да, пишу коряво, извините.
а про visual studio я знаю, просто весит она порядка полутора гигов, так что гораздо проще использовать SharpDevelop

#123.02.2018 03:08
Как удалить клавиатуру после нажатия кнопки ?
#203.03.2018 21:23
сенсорной "назад" на телефоне

Войдите или зарегистрируйтесь чтобы оставить комментарий