Здравствуй, Хабр. Как-то появилось необходимость сделать бота-помощника, но с двумя условиями — использовать WCF сервис и Телеграмм. Так как пришлось потратить достаточное количество времени на реализацию, решил написать статью, возможно кому-то будет полезно.
Создать собственного бота очень просто — заходим в телеграмм, находим специального бота @BotFather, пишем ему команду /newbot и следуем его инструкциям, в результате получаем токен нашего бота.
Теперь надо определиться, каким образом мы будем получать обновления от бота. Telegram предусматривает два способа — тянуть самим с помощью метода getUpdates, либо использовать Webhook. С первым способом все понятно, нам более интересен второй вариант. Используя метод setWebhook можно задать URL вебхука, тем самым вы как бы сообщаете серверам Telegram, куда они должны отправлять все обновления. В роли вебхука как раз будет выступать наш WCF сервис
Создадим новый проект «приложение службы WCF» и назовем его «WcfBot». В документации Telegram сказано, что в обновлениях мы получим объект Update, сериализованный в JSON, поэтому создадим класс этого объекта в новом файле. В этом нам помог json2charp.
Теперь откроем файл IService1.cs, в котором находится интерфейс IService1 с атрибутом ServiceContract — это есть контракт службы. Добавим в него операцию службы и к этой операции допишем атрибут WebInvoke, который определяет, на какой HTTP метод реагирует операция службы, какого формата данные получает и по какому URL обращаться к ней.
IService1.cs
Далее откроем файл Service1.svc.cs и допишем реализацию нашей операции в классе Service1.
Service1.svc.cs
Теперь нам нужно отправлять ответ на сообщение от лица бота. В этом нам поможет библиотека Telegram.Bot. Чтобы её установить, заходим в консоль диспетчера пакетов (Сервис -> Диспетчер пакетов NuGet -> Консоль диспетчера пакетов) и пишем:
Теперь в методе инициализируем объект Telegram.Bot.Api, используя наш token, который нам выдали при создании бота в телеграмме, и реализуем ответ на сообщение “Привет”.
Service1.svc.cs
Осталось подредактировать файл конфигурации Web.config, добавив в behaviors:
и в system.serviceModel:
Теперь можно тестировать. Запускаем сервис, заходим в трей, находим IIS Express, щелкаем правой кнопкой мыши, кликаем «Показать все приложения», находим свой сервис, смотрим по какому порту он включился
Для того, чтобы сервера телеграмм имели доступ к вашему сервису, нужно расшарить localhost. Для этих целей подойдет ngrok.
Скачиваем ngrok, распаковываем, запускаем ngrok.exe и вводим команду:
Вместо 1234 — порт нашего сервиса.
В результате ngrok выдаст нам URL на наш сервис.
Важно скопировать https-версию ссылки, так как Telegram поддерживает только защищенный протокол HTTPS. Теперь осталось лишь сказать нашему боту адрес, куда высылать сообщения. Для этого просто в адресной строке браузера вбиваем ссылку:
Всё, теперь можно написать боту и убедиться, что он действительно отвечает.
[ Исходники ]
Создать собственного бота очень просто — заходим в телеграмм, находим специального бота @BotFather, пишем ему команду /newbot и следуем его инструкциям, в результате получаем токен нашего бота.
Теперь надо определиться, каким образом мы будем получать обновления от бота. Telegram предусматривает два способа — тянуть самим с помощью метода getUpdates, либо использовать Webhook. С первым способом все понятно, нам более интересен второй вариант. Используя метод setWebhook можно задать URL вебхука, тем самым вы как бы сообщаете серверам Telegram, куда они должны отправлять все обновления. В роли вебхука как раз будет выступать наш WCF сервис
Создадим новый проект «приложение службы WCF» и назовем его «WcfBot». В документации Telegram сказано, что в обновлениях мы получим объект Update, сериализованный в JSON, поэтому создадим класс этого объекта в новом файле. В этом нам помог json2charp.
Update.cs
namespace WcfBot
{
public class From
{
public long id { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string username { get; set; }
}
public class Chat
{
public long id { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string username { get; set; }
}
public class ForwardFrom
{
public long id { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string username { get; set; }
}
public class Audio
{
public string file_id { get; set; }
public long duration { get; set; }
public string performer { get; set; }
public string title { get; set; }
public string mime_type { get; set; }
public long file_size { get; set; }
}
public class Thumb
{
public string file_id { get; set; }
public long width { get; set; }
public long height { get; set; }
public long file_size { get; set; }
}
public class Document
{
public string file_id { get; set; }
public Thumb thumb { get; set; }
public string file_name { get; set; }
public string mime_type { get; set; }
public long file_size { get; set; }
}
public class Photo
{
public string file_id { get; set; }
public long width { get; set; }
public long height { get; set; }
public long file_size { get; set; }
}
public class Sticker
{
public string file_id { get; set; }
public string width { get; set; }
public string height { get; set; }
public Thumb thumb { get; set; }
public long file_size { get; set; }
}
public class Video
{
public string file_id { get; set; }
public long width { get; set; }
public long height { get; set; }
public long duration { get; set; }
public Thumb thumb { get; set; }
public string mime_type { get; set; }
public long file_size { get; set; }
}
public class Voice
{
public string file_id { get; set; }
public long duration { get; set; }
public string mime_type { get; set; }
public long file_size { get; set; }
}
public class Contact
{
public string phone_number { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public long user_id { get; set; }
}
public class Location
{
public double longitude { get; set; }
public double latitude { get; set; }
}
public class NewChatParticipant
{
public long id { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string username { get; set; }
}
public class LeftChatParticipant
{
public long id { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string username { get; set; }
}
public class NewChatPhoto
{
public string file_id { get; set; }
public long width { get; set; }
public long height { get; set; }
public long file_size { get; set; }
}
public class ReplyToMessage
{
public long message_id { get; set; }
public From from { get; set; }
public long date { get; set; }
public Chat chat { get; set; }
public ForwardFrom forward_from { get; set; }
public long forward_date { get; set; }
public object reply_to_message { get; set; }
public string text { get; set; }
public Audio audio { get; set; }
public Document document { get; set; }
public IList<Photo> photo { get; set; }
public Sticker sticker { get; set; }
public Video video { get; set; }
public Voice voice { get; set; }
public string caption { get; set; }
public Contact contact { get; set; }
public Location location { get; set; }
public NewChatParticipant new_chat_participant { get; set; }
public LeftChatParticipant left_chat_participant { get; set; }
public string new_chat_title { get; set; }
public IList<NewChatPhoto> new_chat_photo { get; set; }
public bool delete_chat_photo { get; set; }
public bool group_chat_created { get; set; }
}
public class Message
{
public long message_id { get; set; }
public From from { get; set; }
public long date { get; set; }
public Chat chat { get; set; }
public ForwardFrom forward_from { get; set; }
public long forward_date { get; set; }
public ReplyToMessage reply_to_message { get; set; }
public string text { get; set; }
public Audio audio { get; set; }
public Document document { get; set; }
public IList<Photo> photo { get; set; }
public Sticker sticker { get; set; }
public Video video { get; set; }
public Voice voice { get; set; }
public string caption { get; set; }
public Contact contact { get; set; }
public Location location { get; set; }
public NewChatParticipant new_chat_participant { get; set; }
public LeftChatParticipant left_chat_participant { get; set; }
public string new_chat_title { get; set; }
public IList<NewChatPhoto> new_chat_photo { get; set; }
public bool delete_chat_photo { get; set; }
public bool group_chat_created { get; set; }
}
public class Update
{
public long update_id { get; set; }
public Message message { get; set; }
}
}
Теперь откроем файл IService1.cs, в котором находится интерфейс IService1 с атрибутом ServiceContract — это есть контракт службы. Добавим в него операцию службы и к этой операции допишем атрибут WebInvoke, который определяет, на какой HTTP метод реагирует операция службы, какого формата данные получает и по какому URL обращаться к ней.
IService1.cs
namespace WcfBot
{
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = @"/Update")]
void GetUpdate(Update update);
}
}
Далее откроем файл Service1.svc.cs и допишем реализацию нашей операции в классе Service1.
Service1.svc.cs
namespace WcfBot
{
public class Service1 : IService1
{
public void GetUpdate(Update update)
{
}
}
}
Теперь нам нужно отправлять ответ на сообщение от лица бота. В этом нам поможет библиотека Telegram.Bot. Чтобы её установить, заходим в консоль диспетчера пакетов (Сервис -> Диспетчер пакетов NuGet -> Консоль диспетчера пакетов) и пишем:
Install-Package Telegram.Bot
Теперь в методе инициализируем объект Telegram.Bot.Api, используя наш token, который нам выдали при создании бота в телеграмме, и реализуем ответ на сообщение “Привет”.
Service1.svc.cs
namespace WcfBot
{
public class Service1 : IService1
{
public void GetUpdate(Update update)
{
var Bot = new Telegram.Bot.Api("<token>");
if(update.message.text == "Привет")
{
Bot.SendTextMessage(update.message.chat.id, "Привет," + update.message.from.first_name);
}
}
}
}
Осталось подредактировать файл конфигурации Web.config, добавив в behaviors:
<endpointBehaviors>
<behavior name="web">
<webHttp />
</behavior>
</endpointBehaviors>
и в system.serviceModel:
<services>
<service name="WcfBot.Service1">
<endpoint binding="webHttpBinding" contract="WcfBot.IService1" behaviorConfiguration="web"></endpoint>
</service>
</services>
Теперь можно тестировать. Запускаем сервис, заходим в трей, находим IIS Express, щелкаем правой кнопкой мыши, кликаем «Показать все приложения», находим свой сервис, смотрим по какому порту он включился
Для того, чтобы сервера телеграмм имели доступ к вашему сервису, нужно расшарить localhost. Для этих целей подойдет ngrok.
Скачиваем ngrok, распаковываем, запускаем ngrok.exe и вводим команду:
ngrok http 1234 -host-header=”localhost:1234”
Вместо 1234 — порт нашего сервиса.
В результате ngrok выдаст нам URL на наш сервис.
Важно скопировать https-версию ссылки, так как Telegram поддерживает только защищенный протокол HTTPS. Теперь осталось лишь сказать нашему боту адрес, куда высылать сообщения. Для этого просто в адресной строке браузера вбиваем ссылку:
https://api.telegram.org/bot<token>/setWebhook?url=<url>/Service1.svc/Update
Всё, теперь можно написать боту и убедиться, что он действительно отвечает.
[ Исходники ]
Поделиться с друзьями
Комментарии (9)
ZOXEXIVO
06.07.2016 11:15-2Автор вообще понимает, зачем и для чего нужен WCF? Если не понимает, то зачем пишет такие статьи, засоряющие Хабр?
aquamakc
06.07.2016 11:54-2Смешались в кучу кони, люди asp, wcf. Зачем? Есть же замечательный WebClient.
mihmig
06.07.2016 13:04А вот какая у ngrok «пропускная способность»?
timiskhakov
06.07.2016 18:32Пишут, что:
1 online ngrok process
4 tunnels per ngrok process
40 connections / minute
в бесплатном плане. Есть другие.
lair
06.07.2016 13:14Как-то появилось необходимость сделать бота-помощника, но с двумя условиями — использовать WCF сервис и Телеграмм.
А откуда у вас требование на использование WCF? Чем оно обосновано?
(статья представляет собой тривиальный туториал "как собрать бота из двух готовых компонентов")
BlackMetal
06.07.2016 20:59Подписываюсь под словами комментаторов выше. Чем обосновано использование таких костылей и подпорок в 2016?
fcoder
WCF — замечательная и очень гибкая технология, но для подобной задачи мне кажется слишком уж излишней. Гораздо более подходящей здесь мне кажется будет смотреться asp.net стек.
Atreides07
"… файл конфигурации Web.config, добавив в behaviors..." — Автор и использовал ASP.NET. Могли бы уточнить что именно из ASP.NET использовали бы Вы для этой задачи?
Razaz
WebApi. WebInvoke в 2016 году смотрится дико.