[Из песочницы] Как создать Телеграмм бота с помощью WCF сервиса

Здравствуй, Хабр. Как-то появилось необходимость сделать бота-помощника, но с двумя условиями — использовать WCF сервис и Телеграмм. Так как пришлось потратить достаточное количество времени на реализацию, решил написать статью, возможно кому-то будет полезно.

Создать собственного бота очень просто — заходим в телеграмм, находим специального бота @BotFather, пишем ему команду /newbot и следуем его инструкциям, в результате получаем токен нашего бота.

image

Теперь надо определиться, каким образом мы будем получать обновления от бота. 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 { 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 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 { 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 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("");
            if(update.message.text == "Привет")
            {
                Bot.SendTextMessage(update.message.chat.id, "Привет," + update.message.from.first_name);
            }
        }
    }
}

Осталось подредактировать файл конфигурации Web.config, добавив в behaviors:

  
    
  


и в system.serviceModel:

  
    
  


Теперь можно тестировать. Запускаем сервис, заходим в трей, находим IIS Express, щелкаем правой кнопкой мыши, кликаем «Показать все приложения», находим свой сервис, смотрим по какому порту он включился
image

Для того, чтобы сервера телеграмм имели доступ к вашему сервису, нужно расшарить localhost. Для этих целей подойдет ngrok.

Скачиваем ngrok, распаковываем, запускаем ngrok.exe и вводим команду:

ngrok http 1234 -host-header=”localhost:1234

Вместо 1234 — порт нашего сервиса.

В результате ngrok выдаст нам URL на наш сервис.

image

Важно скопировать https-версию ссылки, так как Telegram поддерживает только защищенный протокол HTTPS. Теперь осталось лишь сказать нашему боту адрес, куда высылать сообщения. Для этого просто в адресной строке браузера вбиваем ссылку:

https://api.telegram.org/bot<token>/setWebhook?url=<url>/Service1.svc/Update

Всё, теперь можно написать боту и убедиться, что он действительно отвечает.

image

[ Исходники ]

Комментарии (2)

  • 6 июля 2016 в 09:25

    0

    WCF — замечательная и очень гибкая технология, но для подобной задачи мне кажется слишком уж излишней. Гораздо более подходящей здесь мне кажется будет смотреться asp.net стек.
    • 6 июля 2016 в 10:08

      0

      »… файл конфигурации Web.config, добавив в behaviors…» — Автор и использовал ASP.NET. Могли бы уточнить что именно из ASP.NET использовали бы Вы для этой задачи?

© Habrahabr.ru