Простой Telegram.Bot мессенджер на C#

от автора

Часть 1

Почему?

Решил я попрактиковаться в написании приложений на шарпе с использованием EF. Пока разбирался заметил, что туториалов и примеров как написать бота на C# немного, поэтому решил поделиться своими наработками.

Что может бот:

Задача бота — устроить обмен сообщениями между главным и подчиненными так, чтобы главный(диспетчер) мог писать всем или только одному подчиненному(водителю), а подчиненные могли общаться только с главным. WebHook не нужен, т.к. бот сугубо для практики.

Модель БД

Итак, для начала решил описать все необходимые таблицы, для хранения информации. Однако по итогу модель немного изменилась.

Шаг 1:

Для хранения таблиц я использовал Postgre SQL 15, а для мониторинга PgAdmin 4. Создал бд Users и развернул локально.

скачать

Шаг 2:

Установим все необходимые пакеты в VS через NuGET:

  • Microsoft.EntityFrameworkCore.Tools

  • Newtonsoft.Json

  • Npgsql.EntityFrameworkCore.PostgreSQL

  • Telegram.Bot

  • Telegram.Bot.Extensions.Polling

Шаг 3:

Получаем токен https://telegram.me/BotFather и плавно переходим к коду.

Шаг 4:

Создадим пустой класс Program.cs и внесем в него все необходимые для работы Методы:

using Telegram.Bot; using Telegram.Bot.Extensions.Polling; using Telegram.Bot.Types.ReplyMarkups; using CETmsgr.keyboards; using CETmsgr.dbutils; using Update = Telegram.Bot.Types.Update; using Telegram.Bot.Types.Enums;  namespace CETmsgr {     class Program     {         static ITelegramBotClient bot = new TelegramBotClient("TOKEN");         public static async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken)         {             Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(update));           if (update.Type == UpdateType.Message)           {           // Тут бот получает сообщения от пользователя             // Дальше код отвечает за команду старт, которую можно добавить через botfather             // Если все хорошо при запуске program.cs в консоль выведется, что бот запущен             // а при отправке команды бот напишет Привет             if (message.Text.ToLower() == "/start")                 {                     await DataBaseMethods.ToggleInDialogStatus(update.Message.Chat.Id, 0);                     await botClient.SendTextMessageAsync(                         chatId: message.Chat,                         text: "Привет");                      return;           }           if (update.Type == UpdateType.CallbackQuery)           {           // Тут получает нажатия на inline кнопки           }           public static async Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken)         {             // Данный Хендлер получает ошибки и выводит их в консоль в виде JSON             Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(exception));         }         static void Main(string[] args)         {              Console.WriteLine("Запущен бот " + bot.GetMeAsync().Result.FirstName);             var cts = new CancellationTokenSource();             var cancellationToken = cts.Token;             var receiverOptions = new ReceiverOptions             {                 AllowedUpdates = { }, // разрешено получать все виды апдейтов             };             bot.StartReceiving(                 HandleUpdateAsync,                 HandleErrorAsync,                 receiverOptions,                 cancellationToken             );             Console.ReadLine();                      }     } }

Шаг 5:

Теперь приступим к созданию классов для таблиц, я создал отдельную папку dbutils для этих нужд.

UserRoles необходима для того, чтобы можно было сортировать id пользователей по ролям.

TrafficControllers и Drivers просто будут хранить информацию по юзерам.

DialogMembers будет хранить уникальные id диалогов и связывать их между id 2х юзеров

DialogMsgs эта таблица будет хранить сообщения, связанные с id диалога из DialogMembers

DialogStatus а вот эта таблица необходима для проверок при написании сообщений юзеров боту.

using System.ComponentModel.DataAnnotations;  namespace CETmsgr.dbutils {     public partial class UserRoles     {         [Key]         public long TgId { get; set; }         public string Role { get; set; }         public string? TgUsername { get; set; }         public long TgChatId { get; set; }         public int StageReg { get; set; }      } }
using System.ComponentModel.DataAnnotations;  namespace CETmsgr.dbutils {     public partial class Drivers     {         [Key]         public long IdDriver { get; set; }         public string Name { get; set; }         public string IdRoute { get; set; }         public string VehichleRegNum { get; set; }         public string DeviceSerialNum { get; set; }     } }
using System.ComponentModel.DataAnnotations;  namespace CETmsgr.dbutils {     public partial class TrafficControllers     {         [Key]         public long IdTc { get; set; }         public string Name { get; set; }     } }
using System.ComponentModel.DataAnnotations;  namespace CETmsgr.dbutils {     public partial class DialogMembers     {         [Key]         public int IdThread { get; set; }         public long IdTc { get; set; }         public long IdDriver { get; set; }     } }
using System.ComponentModel.DataAnnotations;  namespace CETmsgr.dbutils {     public partial class DialogMsgs     {         [Key]         public long IdUnique { get; set; }         public int IdThread { get; set; }         public string Created { get; set; }         public string UrgentLevel { get; set; }         public string Message { get; set; }     } }
using System.ComponentModel.DataAnnotations;  namespace CETmsgr.dbutils {     public partial class DialogStatus     {         [Key]         public long TgId { get; set; }         public int Status { get; set; }         public long CurrentDialog { get; set; }      } }

Чтобы на основании этого добра появились таблицы в бд необходимо провести миграцию. Поэтому создаем модель данных для наших классов и задаем подключение к бд:

using Microsoft.EntityFrameworkCore;  namespace CETmsgr.dbutils {     public class ApplicationContext : DbContext     {         public DbSet<UserRoles> UserRoles { get; set; }         public DbSet<Drivers> Drivers { get; set; }         public DbSet<TrafficControllers> TrafficControllers { get; set; }         public DbSet<DialogMsgs> DialogMsgs { get; set; }         public DbSet<DialogMembers> DialogMembers { get; set; }         public DbSet<DialogStatus> DialogStatus { get; set; }          protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)         {             optionsBuilder.UseNpgsql(                 "Host=localhost;" +                 "Port=5433;" +                 "Database=Users;" +                 "Username=postgres;" +                 "Password=zaqwsxzaq");         }     } }      

теперь выполняем миграцию:

для этого в консоль диспетчера пакетов вводим команды:

enable-migrations
Add-migration *Имя миграции*
update-database

теперь когда есть таблицы для хранения всех необходимых данных можем приступать к написанию логики.

Шаг 6:

Итак для работы с БД, нам необходимо написать методов для работы с ним. для этого в раннее созданную папку создаем файл DataBaseMethods.cs. Поскольку мой бот уже готов я выложу исходный файл, дабы не запутывать вас раздельным повествованием.

using Microsoft.EntityFrameworkCore; using System.Data;  namespace CETmsgr.dbutils {     internal class DataBaseMethods     {         // метод для создания сообщения водителем. данные методы мне кажутся излишними, но я решил их оставить тк все работает         public static async Task<long> MsgCreateByDriverToTc(int IdThread, string Msg, string Crtd, string UL)         {             using (ApplicationContext db = new ApplicationContext())             {                 DialogMsgs newMSG = new DialogMsgs { IdThread = IdThread, Created = Crtd, UrgentLevel = UL, Message = Msg };                 await db.DialogMsgs.AddAsync(newMSG);                 await db.SaveChangesAsync();                 try                 {                     var getMSG = await db.DialogMsgs.OrderBy(x => x.Created).LastOrDefaultAsync(x => x.IdThread == IdThread);                     return getMSG.IdUnique;                 }                 catch(Exception ex)                 {                     return 123123;                 }                              }         }         // метод для создания сообщения диспетчером         public static async Task<long> MsgCreateByTcToDriver(int IdThread, string Msg, string Crtd, string UL)         {             using (ApplicationContext db = new ApplicationContext())             {                 DialogMsgs newMSG = new DialogMsgs { IdThread = IdThread, Created = Crtd, UrgentLevel = UL, Message = Msg };                 await db.DialogMsgs.AddAsync(newMSG);                 await db.SaveChangesAsync();                 try                 {                     var getMSG = await db.DialogMsgs.OrderBy(x => x.IdUnique).LastOrDefaultAsync(x => x.IdThread == IdThread);                     return getMSG.IdUnique;                 }                 catch (Exception ex)                 {                     return 123123;                 }              }         }         // метод для получения сообщений диспетчером         public static async Task<long> MsgRecievierTc(long IdUnique, int IdThread, long IdDriver)         {             using (ApplicationContext db = new ApplicationContext())             {                 var getMSG = await db.DialogMsgs.FirstOrDefaultAsync(x => x.IdUnique == IdUnique);                 var getId = await db.DialogMembers.FirstOrDefaultAsync(x => (x.IdThread == IdThread && x.IdDriver == IdDriver));                 if (getMSG.IdThread == getId.IdThread)                 {                     return getId.IdTc;                 }                 else                 {                     return 404;                 }             }         }         // метод для получения сообщений водителем          public static async Task<long> MsgRecievierDriver(long IdUnique, int IdThread, long IdTc)         {             using (ApplicationContext db = new ApplicationContext())             {                 var getMSG = await db.DialogMsgs.FirstOrDefaultAsync(x => x.IdUnique == IdUnique);                 var getId = await db.DialogMembers.FirstOrDefaultAsync(x => (x.IdThread == IdThread && x.IdTc == IdTc));                 if (getMSG.IdThread == getId.IdThread)                 {                     return getId.IdDriver;                 }                 else                 {                     return 404;                 }             }         }         // получение стаутса пользователя, чтобы бот мог разделять сообщения от пользователя по данному фильтру         public static async Task<int> GetStatus(long TgId)         {             using (ApplicationContext db = new ApplicationContext())             {                 var status = await db.DialogStatus.FirstOrDefaultAsync(x => x.TgId == TgId);                 return status.Status;             }         }         // получение id юзера для отправки сообщения через бота из другого юзера при условии нажатия кнопок в диалогах         public static async Task<long> GetAddress(long TgId)         {             using (ApplicationContext db = new ApplicationContext())             {                 var status = await db.DialogStatus.FirstOrDefaultAsync(x => x.TgId == TgId);                 return status.CurrentDialog;             }         }         // получение id диалога из бд         public static async Task<int> GetThreadByDriver(long IdDriver)         {             using (ApplicationContext db = new ApplicationContext())             {                 var dialog = await db.DialogMembers.FirstOrDefaultAsync(x => x.IdDriver == IdDriver);                 return dialog.IdThread;             }         }         // получение id диалога из бд         public static async Task<int> GetThreadByTc(long IdTc, long IdDriver)         {             using (ApplicationContext db = new ApplicationContext())             {                 var dialog = await db.DialogMembers.FirstOrDefaultAsync(x => x.IdTc == IdTc && x.IdDriver == IdDriver);                 return dialog.IdThread;             }         }         // получение роли юзера         public static async Task<UserRoles> GetUserRole(long TgId)         {             using (ApplicationContext db = new ApplicationContext())             {                 var user = await db.UserRoles.FirstOrDefaultAsync(x => x.TgId == TgId);                 return user;             }         }         // получение данных водителя         public static async Task<Drivers> GetDriverData(long IdDriver)         {             using (ApplicationContext db = new ApplicationContext())             {                 var driver = await db.Drivers.FirstOrDefaultAsync(x => x.IdDriver == IdDriver);                 return driver;             }         }         // получение данных диспетчера         public static async Task<TrafficControllers> GetTcData(long IdTc)         {             using (ApplicationContext db = new ApplicationContext())             {                 var tc = await db.TrafficControllers.FirstOrDefaultAsync(x => x.IdTc == IdTc);                 return tc;             }         }         // обновление статуса юзера и id получателя сообщения         public static async Task ToggleInDialogStatus(long TgId, int Status, long receivier)         {             using (ApplicationContext db = new ApplicationContext())             {                 var dialogStatus = await db.DialogStatus.FirstOrDefaultAsync(x => x.TgId == TgId );                 if (dialogStatus is null)                 {                     DialogStatus StatusCreate = new DialogStatus { TgId = TgId, Status = Status, CurrentDialog = receivier};                     var result = await db.DialogStatus.AddAsync(StatusCreate);                     await db.SaveChangesAsync();                 }                 else                 {                     dialogStatus.Status = Status;                     dialogStatus.CurrentDialog = receivier;                     db.DialogStatus.Update(dialogStatus);                     await db.SaveChangesAsync();                 }             }         }         // обновление статуса юзера         public static async Task ToggleInDialogStatus(long TgId, int Status)         {             using (ApplicationContext db = new ApplicationContext())             {                 var dialogStatus = await db.DialogStatus.FirstOrDefaultAsync(x => x.TgId == TgId);                 if (dialogStatus is null)                 {                     DialogStatus StatusCreate = new DialogStatus { TgId = TgId, Status = Status, CurrentDialog = 0 };                     var result = await db.DialogStatus.AddAsync(StatusCreate);                     await db.SaveChangesAsync();                 }                 else                 {                     dialogStatus.Status = Status;                     dialogStatus.CurrentDialog = 0;                     db.DialogStatus.Update(dialogStatus);                     await db.SaveChangesAsync();                 }             }         }         // добавление или обновление юзера         public static async Task AddOrUpdateUser(long tg_ID, string role, string tg_username, long tg_chat_id, int StageReg)         {             using (ApplicationContext db = new ApplicationContext())             {                 var user = await db.UserRoles.FirstOrDefaultAsync(x => x.TgId == tg_ID);                 if (user is null)                 {                     if (tg_username == null)                     {                         tg_username = "Без ника";                     }                     UserRoles newuser = new UserRoles { TgId = tg_ID, Role = role, TgUsername = tg_username, TgChatId = tg_chat_id, StageReg = StageReg };                     await db.UserRoles.AddAsync(newuser);                     await db.SaveChangesAsync();                 }                 else                 {                     user.Role = role;                     user.TgUsername = tg_username;                     db.UserRoles.Update(user);                     await db.SaveChangesAsync();                 }             }          }         // создание диалога         public static async Task DialogCreate(long IdTc, long IdDriver)         {             using (ApplicationContext db = new ApplicationContext())             {                 var dialogWithDriver = await db.DialogMembers.FirstOrDefaultAsync(x => x.IdDriver == IdDriver && x.IdTc == IdTc);                 if (dialogWithDriver is null)                 {                     DialogMembers newDialog = new DialogMembers { IdDriver = IdDriver, IdTc = IdTc };                     var result = await db.DialogMembers.AddAsync(newDialog);                     await db.SaveChangesAsync();                 }                 else                 {                  }             }         }         // изменение статуса пользователя         public static async Task StageIncrement(long tg_ID, int StageReg)         {             using (ApplicationContext db = new ApplicationContext())             {                 var user = await db.UserRoles.FirstOrDefaultAsync(x => x.TgId == tg_ID);                 user.StageReg = StageReg;                 db.UserRoles.Update(user);                 await db.SaveChangesAsync();             }         }         // добавление водителя до регистрации все строки по нулям, чтобы exception не словить         public static async Task AddDriver(long IdDriver)         {             using (ApplicationContext db = new ApplicationContext())             {                 var user = await db.Drivers.FirstOrDefaultAsync(x => x.IdDriver == IdDriver);                 if (user is null)                 {                 string Name = "0";                 string IdRoute = "0";                 string VehichleRegNum = "0";                 string DeviceSerialNum = "0";                 Drivers newDriver = new Drivers { IdDriver = IdDriver, Name = Name, IdRoute = IdRoute, VehichleRegNum = VehichleRegNum, DeviceSerialNum = DeviceSerialNum};                 var result = db.Drivers.AddAsync(newDriver);                 await db.SaveChangesAsync();                 }                              }         }         // добавление диспетчера         public static async Task AddTc(long IdTc)         {             using (ApplicationContext db = new ApplicationContext())             {                 var user = await db.TrafficControllers.FirstOrDefaultAsync(x => x.IdTc == IdTc);                 if (user is null)                 {                     string Name = "0";                     TrafficControllers newTc = new TrafficControllers { IdTc = IdTc, Name = Name};                     var result = await db.TrafficControllers.AddAsync(newTc);                     await db.SaveChangesAsync();                 }              }         }         // добавление данных в бд водителя         public static async Task AddDataDriverName(long IdDriver, string Name)         {             using (ApplicationContext db = new ApplicationContext())             {                 var Driver = await db.Drivers.FirstOrDefaultAsync(x => x.IdDriver == IdDriver);                 Driver.Name = Name;                 db.Drivers.Update(Driver);                 await db.SaveChangesAsync();             }         }         public static async Task AddDataDriverIdRoute(long IdDriver, string IdRoute)         {             using (ApplicationContext db = new ApplicationContext())             {                 var Driver = await db.Drivers.FirstOrDefaultAsync(x => x.IdDriver == IdDriver);                 Driver.IdRoute = IdRoute;                 db.Drivers.Update(Driver);                 await db.SaveChangesAsync();             }         }         public static async Task AddDataDriverVehichleRegNum(long IdDriver, string VehichleRegNum)         {             using (ApplicationContext db = new ApplicationContext())             {                 var Driver = await db.Drivers.FirstOrDefaultAsync(x => x.IdDriver == IdDriver);                 Driver.VehichleRegNum = VehichleRegNum;                 db.Drivers.Update(Driver);                 await db.SaveChangesAsync();             }         }         public static async Task AddDataDriverDeviceSerialNum(long IdDriver, string DeviceSerialNum)         {             using (ApplicationContext db = new ApplicationContext())             {                 var Driver = await db.Drivers.FirstOrDefaultAsync(x => x.IdDriver == IdDriver);                 Driver.DeviceSerialNum = DeviceSerialNum;                 db.Drivers.Update(Driver);                 await db.SaveChangesAsync();             }         }         // добавление данных в бд диспетчера         public static async Task AddDataTcName(long IdDriver, string Name)         {             using (ApplicationContext db = new ApplicationContext())             {                 var tc = await db.TrafficControllers.FirstOrDefaultAsync(x => x.IdTc == IdDriver);                 tc.Name = Name;                 db.TrafficControllers.Update(tc);                 await db.SaveChangesAsync();             }         }         // вывод списка водителей         public static List<long> GetAllDriversId(string role)         {             //Dictionary<long, string> driversId_Name = new Dictionary<long, string>();             using (ApplicationContext db = new ApplicationContext())             {                 var AllDrivers = db.UserRoles.Where(x => x.Role == role).ToList();                 List<long> driversIDs = new List<long>();                 foreach (var u in AllDrivers)                     driversIDs.Add(u.TgId);                 return driversIDs;             }          }     } }

Финал:

Теперь можно рассмотреть логику реагирования бота на нажатия и сообщения. Поэтому опишем все необходимые кнопки в классе kb.

namespace CETmsgr.keyboards {     public static class kb     {         public static ReplyKeyboardMarkup Register = new(new[]         {             new KeyboardButton[] { "/reg" },         })         { ResizeKeyboard = true };         public static InlineKeyboardMarkup Role = new(new[]         {             new []             {                 InlineKeyboardButton.WithCallbackData(text: "Водитель", callbackData: "driver"),                 InlineKeyboardButton.WithCallbackData(text: "Диспетчер", callbackData: "controller"),             },         });         public static InlineKeyboardMarkup Menu = new(new[]         {             new []             {                 InlineKeyboardButton.WithCallbackData(text: "Диалоги", callbackData: "dialogs"),                 InlineKeyboardButton.WithCallbackData(text: "Профиль", callbackData: "profile"),             },             //new []             //{             //    InlineKeyboardButton.WithCallbackData(text: "Регистрация", callbackData: "register"),             //},         });         public static InlineKeyboardMarkup ToMenu = new(new[]         {             new []             {                 InlineKeyboardButton.WithCallbackData(text: "Меню", callbackData: "menu"),             },         });          public static InlineKeyboardMarkup StartRegDriver = new(new[]         {             new []             {                 InlineKeyboardButton.WithCallbackData(text: "Ваше ФИО", callbackData: "DriverName"),             },             new []             {                 InlineKeyboardButton.WithCallbackData(text: "Идентификатор маршрута", callbackData: "IdRoute"),             },                         new []             {                 InlineKeyboardButton.WithCallbackData(text: "Регистрационный номер тс", callbackData: "VehichleRegNum"),             },                       new []             {                 InlineKeyboardButton.WithCallbackData(text: "Серийный номер устройства", callbackData: "DeviceSerialNum"),             },             new []             {                 InlineKeyboardButton.WithCallbackData(text: "Окончить Регистрацию", callbackData: "FinReg"),             },         });         public static InlineKeyboardMarkup StartRegTC = new(new[]         {             new []             {                 InlineKeyboardButton.WithCallbackData(text: "Ваше ФИО", callbackData: "TcName"),             },             new []             {                 InlineKeyboardButton.WithCallbackData(text: "Окончить Регистрацию", callbackData: "FinReg"),             },         });         public static InlineKeyboardMarkup MsgToDriver = new(new[]         {             new []             {                 InlineKeyboardButton.WithCallbackData(text: "Водитель", callbackData: "driver"),                 InlineKeyboardButton.WithCallbackData(text: "Диспетчер", callbackData: "controller"),             },         });         public static InlineKeyboardMarkup MsgDispetcher = new(new[]         {             new []             {                 InlineKeyboardButton.WithCallbackData(text: "Диспетчер", callbackData: "callTC"),             },         });         public static InlineKeyboardMarkup TextAll = new(new[]         {             new []             {                 InlineKeyboardButton.WithCallbackData(text: "Написать всем", callbackData: "textall"),             },         });     } }

Вернемся в класс program

using Telegram.Bot; using Telegram.Bot.Extensions.Polling; using Telegram.Bot.Types.ReplyMarkups; using CETmsgr.keyboards; using CETmsgr.dbutils; using Update = Telegram.Bot.Types.Update; using Telegram.Bot.Types.Enums;  namespace CETmsgr {       class Program     {         static ITelegramBotClient bot = new TelegramBotClient("TOKEN");         public static async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken)         {             Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(update));                          if (update.Type == UpdateType.Message)             {                 string Time = DateTime.Now.ToShortTimeString();                 var message = update.Message;                  if (message.Text.ToLower() == "/reg")                 {                     await DataBaseMethods.ToggleInDialogStatus(update.Message.Chat.Id, 0);                     await botClient.SendTextMessageAsync(                         message.Chat.Id,                         "загрузка...",                         replyMarkup: new ReplyKeyboardRemove());                      var userData = await DataBaseMethods.GetUserRole(message.From.Id);                     if (userData != null)                     {                         await botClient.SendTextMessageAsync(                             message.Chat.Id,                             text: "Вы уже зарегистрировались",                             replyMarkup: kb.ToMenu);                     }                     else                     {                          await botClient.SendTextMessageAsync(                             message.Chat.Id,                             text: "Выберите свою должность",                             replyMarkup: kb.Role);                     }                     return;                 }                 if (message.Text.ToLower() == "/start")                 {                     await DataBaseMethods.ToggleInDialogStatus(update.Message.Chat.Id, 0);                     await botClient.SendTextMessageAsync(                         chatId: message.Chat,                         text: "Главное меню",                         replyMarkup: kb.Menu);                      return;                 } // это условие для того, чтобы команды не попадали туда куда не надо                 if (!message.Text.StartsWith("/"))                 {                     int dialogStatus = await DataBaseMethods.GetStatus(message.Chat.Id);                     var userDataReg = await DataBaseMethods.GetUserRole(message.Chat.Id);                     string role = userDataReg.Role;                     int countReg = userDataReg.StageReg; // так выглядит регистрациЯ ДИСПЕТЧЕРА И ВОДИТЕЛЯ, собственно счетчики нужны для корректного отслеживания сообщений от пользователя                                         if (countReg == 1 && role == "driver" && dialogStatus == 0)                     {                         await DataBaseMethods.AddDataDriverName(message.From.Id, message.Text);                     }                     if (countReg == 1 && role == "controller" && dialogStatus == 0)                     {                         await DataBaseMethods.AddDataTcName(message.From.Id, message.Text);                         await botClient.SendTextMessageAsync(                             message.Chat.Id,                             text: "Хотите вернуться в меню?",                             replyMarkup: kb.ToMenu);                     }                     if (countReg == 2 && dialogStatus == 0)                     {                         await DataBaseMethods.AddDataDriverIdRoute(message.From.Id, message.Text);                     }                     if (countReg == 3 && dialogStatus == 0)                     {                         await DataBaseMethods.AddDataDriverVehichleRegNum(message.From.Id, message.Text);                     }                     if (countReg == 4 && dialogStatus == 0)                     {                         await DataBaseMethods.AddDataDriverDeviceSerialNum(message.From.Id, message.Text);                         await botClient.SendTextMessageAsync(                             message.Chat.Id,                             text: "Хотите вернуться в меню?",                             replyMarkup: kb.ToMenu);                     } // а вот пригодились статусы, чтобы оставаться в неком диалоге, внутри бота, // пока юзер не вернется в меню                      if (role == "driver" && dialogStatus == 1)                     {                         var getDialog = await DataBaseMethods.GetThreadByDriver(                             message.Chat.Id);                         var msgID = await DataBaseMethods.MsgCreateByDriverToTc(                             getDialog,                             message.Text,                             Time,                             "3");                         var reciever = await DataBaseMethods.MsgRecievierTc(msgID, getDialog, message.Chat.Id);                         var msgFrom = await DataBaseMethods.GetDriverData(message.Chat.Id);                         await botClient.SendTextMessageAsync(                             reciever,                             text: $"{msgFrom.Name}:" + "\n" +                             $"Маршрут: {msgFrom.IdRoute}:" + "\n" +                             $"{message.Text}");                     }                     if (role == "controller" && dialogStatus == 1)                     {                         var getAddress = await DataBaseMethods.GetAddress(message.Chat.Id);                         var getDialog = await DataBaseMethods.GetThreadByTc(                             message.Chat.Id,                             IdDriver: getAddress);                         var msgID = await DataBaseMethods.MsgCreateByTcToDriver(                             getDialog,                             message.Text,                             Time,                             "3");                         var reciever = await DataBaseMethods.MsgRecievierDriver(msgID, getDialog, message.Chat.Id);                         var msgFrom = await DataBaseMethods.GetTcData(message.Chat.Id);                         await botClient.SendTextMessageAsync(                             reciever,                             text: $"{msgFrom.Name}:" + "\n" +                             $"{message.Text}");                     } // это отдельная фича под рассылку всем В от Д в боте                     if (role == "controller" && dialogStatus == 2)                     {                         var getAddress = DataBaseMethods.GetAllDriversId("driver");                         foreach (var address in getAddress)                         {                             var getDialog = await DataBaseMethods.GetThreadByTc(                                 message.Chat.Id,                                 IdDriver: address);                             var msgID = await DataBaseMethods.MsgCreateByTcToDriver(                                 getDialog,                                 message.Text,                                 Time,                                 "3");                             var reciever = await DataBaseMethods.MsgRecievierDriver(msgID, getDialog, message.Chat.Id);                             var msgFrom = await DataBaseMethods.GetTcData(message.Chat.Id);                             await botClient.SendTextMessageAsync(                                 reciever,                                 text: $"{msgFrom.Name}:" + "\n" +                                 $"{message.Text}");                         }                     }                     else                         return;                 }             }             if (update.Type == UpdateType.CallbackQuery)             { // Тут идет обработка всех нажатий на кнопки, тут никаких особых доп условий не надо, тк у каждой кнопки своя ссылка                 var callbackQuery = update.CallbackQuery;                 var userRole = await DataBaseMethods.GetUserRole(callbackQuery.Message.Chat.Id);                 long userTgId;                 try                 {                     userTgId = Convert.ToInt64(callbackQuery.Data);                 }                 catch                 {                     userTgId = 0;                 }                 var checkUserCallback = await DataBaseMethods.GetUserRole(userTgId); // тут единственнок место где условие чуть сложнее // здесь по простому мы запоминаем ид пользвоателя в отд бд, откуда в дальнейем рлдгрузим данные               if (checkUserCallback != null)                 {                     if (callbackQuery.Data == checkUserCallback.TgId.ToString() != null && userRole.Role == "controller")                     {                         await DataBaseMethods.DialogCreate(userTgId, callbackQuery.Message.Chat.Id);                         await DataBaseMethods.ToggleInDialogStatus(callbackQuery.Message.Chat.Id, 1, userTgId);                         await botClient.SendTextMessageAsync(                             callbackQuery.Message.Chat.Id,                             text: "Напишите сообщение водителю",                             replyMarkup: kb.ToMenu);                     }                     if (callbackQuery.Data == checkUserCallback.TgId.ToString() && userRole.Role == "driver")                     {                         await DataBaseMethods.DialogCreate(userTgId, callbackQuery.Message.Chat.Id);                         await DataBaseMethods.ToggleInDialogStatus(callbackQuery.Message.Chat.Id, 1, userTgId);                         await botClient.SendTextMessageAsync(                             callbackQuery.Message.Chat.Id,                             text: "Напишите сообщение диспетчеру",                             replyMarkup: kb.ToMenu);                     }                 }                 if (callbackQuery.Data == "menu")                 {                     await DataBaseMethods.ToggleInDialogStatus(callbackQuery.Message.Chat.Id, 0);                     await botClient.DeleteMessageAsync(                             callbackQuery.Message.Chat.Id,                             callbackQuery.Message.MessageId);                      await botClient.SendTextMessageAsync(                         callbackQuery.Message.Chat.Id,                         text: "Главное Меню",                         replyMarkup: kb.Menu);                 }                 if (callbackQuery.Data == "register")                 {                     await botClient.SendTextMessageAsync(                             callbackQuery.Message.Chat.Id,                             "/reg это способ пройти регистрацию");                  }                 if (callbackQuery.Data == "profile")                 {                     await botClient.DeleteMessageAsync(                             callbackQuery.Message.Chat.Id,                             callbackQuery.Message.MessageId);                      var driverData = await DataBaseMethods.GetDriverData(callbackQuery.Message.Chat.Id);                     var tcData = await DataBaseMethods.GetTcData(callbackQuery.Message.Chat.Id);                     if (userRole != null && driverData != null)                     {                         var name = driverData.Name;                         var route = driverData.IdRoute;                         var vrn = driverData.VehichleRegNum;                         var dsn = driverData.DeviceSerialNum;                         var role = userRole.Role;                         await botClient.SendTextMessageAsync(                             callbackQuery.Message.Chat.Id,                             text: $"ваша должность: {role}");                         await botClient.SendTextMessageAsync(                             callbackQuery.Message.Chat.Id,                             text: $"Ваше ФИО: {name}" + "\n" +                             $"Маршрут номер: {route}" + "\n" +                             $"Номер тс: {vrn}" + "\n" +                             $"Номер устройства: {dsn}");                     }                     if (userRole != null && tcData != null)                     {                         var name = tcData.Name;                         var role = userRole.Role;                         await botClient.SendTextMessageAsync(                             callbackQuery.Message.Chat.Id,                             text: $"ваша должность: {role}");                         await botClient.SendTextMessageAsync(                             callbackQuery.Message.Chat.Id,                             text: $"Ваше ФИО: {name}");                     }                     else                     {                         await botClient.SendTextMessageAsync(                             callbackQuery.Message.Chat.Id,                             text: "для регистрации нажмите /reg",                             replyMarkup: kb.Register);                     }                      await botClient.SendTextMessageAsync(                         callbackQuery.Message.Chat.Id,                         text: "Хотите вернуться в меню?",                         replyMarkup: kb.ToMenu);                 }                 if (callbackQuery.Data == "dialogs")                 {                     var role = userRole.Role;                     if (role == "controller")                     {                         await botClient.DeleteMessageAsync(                             callbackQuery.Message.Chat.Id,                             callbackQuery.Message.MessageId);                          var driversList = DataBaseMethods.GetAllDriversId("driver");                          await botClient.SendTextMessageAsync(                             callbackQuery.Message.Chat.Id,                             "Водители:",                             replyMarkup: kb.TextAll);                          foreach (var driver in driversList)                         {                             var driverName = await DataBaseMethods.GetDriverData(driver);                             InlineKeyboardMarkup driverButton = new(new[]                             {                                     new []                                     {                                         InlineKeyboardButton.WithCallbackData(text: $"{driver}", callbackData: $"{driver}"),                                     },                                 });                             await botClient.SendTextMessageAsync(                                 callbackQuery.Message.Chat.Id,                                 $"<code>{driverName.Name}</code> ",                                 ParseMode.Html,                                 replyMarkup: driverButton);                         }                     }                     else                     {                         await botClient.DeleteMessageAsync(                             callbackQuery.Message.Chat.Id,                             callbackQuery.Message.MessageId);                          var tcList = DataBaseMethods.GetAllDriversId("controller");                          await botClient.SendTextMessageAsync(                             callbackQuery.Message.Chat.Id,                             "Диспетчеры:");                          foreach (var tc in tcList)                         {                             var tcName = await DataBaseMethods.GetTcData(tc);                             InlineKeyboardMarkup tcButton = new(new[]                             {                                     new []                                     {                                         InlineKeyboardButton.WithCallbackData(text: $"{tc}", callbackData: $"{tc}"),                                     },                                 });                             await botClient.SendTextMessageAsync(                                 callbackQuery.Message.Chat.Id,                                 $"<code>{tcName.Name}</code> ",                                 ParseMode.Html,                                 replyMarkup: tcButton);                         }                     }                 }                 if (callbackQuery.Data == "textall")                 {                     var allDrivers = DataBaseMethods.GetAllDriversId("driver");                     foreach (long driver in allDrivers)                     {                         await DataBaseMethods.DialogCreate(callbackQuery.Message.Chat.Id, driver);                         await DataBaseMethods.ToggleInDialogStatus(callbackQuery.Message.Chat.Id, 2, driver);                     }                     await botClient.SendTextMessageAsync(                         callbackQuery.Message.Chat.Id,                         text: "Напишите сообщение для всех водителей",                         replyMarkup: kb.ToMenu);                 }                 if (callbackQuery.Data == "driver")                 {                     await botClient.DeleteMessageAsync(                             callbackQuery.Message.Chat.Id,                             callbackQuery.Message.MessageId);                      await botClient.SendTextMessageAsync(                         callbackQuery.Message.Chat.Id,                         text: "Нажмите на кнопку для ввода данных",                         replyMarkup: kb.StartRegDriver);                      int StageRegDriver = 1;                     await DataBaseMethods.AddOrUpdateUser(                         callbackQuery.Message.Chat.Id,                         callbackQuery.Data.ToString(),                         callbackQuery.From.Username,                         callbackQuery.Message.From.Id,                         StageRegDriver);                      await DataBaseMethods.AddDriver(                         callbackQuery.Message.Chat.Id);                 } // начало регистрации Водителя                 if (callbackQuery.Data == "DriverName")                 {                     await DataBaseMethods.StageIncrement(callbackQuery.Message.Chat.Id, 1);                     await botClient.SendTextMessageAsync(                         callbackQuery.Message.Chat.Id,                         text: "Введите ФИО:");                 }                 if (callbackQuery.Data == "IdRoute")                 {                     await DataBaseMethods.StageIncrement(callbackQuery.Message.Chat.Id, 2);                     await botClient.SendTextMessageAsync(                         callbackQuery.Message.Chat.Id,                         text: "Введите номер маршрута:");                 }                 if (callbackQuery.Data == "VehichleRegNum")                 {                     await DataBaseMethods.StageIncrement(callbackQuery.Message.Chat.Id, 3);                     await botClient.SendTextMessageAsync(                         callbackQuery.Message.Chat.Id,                         text: "Введите номер тс:");                 }                 if (callbackQuery.Data == "DeviceSerialNum")                 {                     await DataBaseMethods.StageIncrement(callbackQuery.Message.Chat.Id, 4);                     await botClient.SendTextMessageAsync(                         callbackQuery.Message.Chat.Id,                         text: "Введите номер устройства:");                 }                 if (callbackQuery.Data == "controller")                 {                     await botClient.DeleteMessageAsync(                             callbackQuery.Message.Chat.Id,                             callbackQuery.Message.MessageId);                      await botClient.SendTextMessageAsync(                         callbackQuery.Message.Chat.Id,                         text: "Нажмите на кнопку для ввода данных",                         replyMarkup: kb.StartRegTC);                      int StageRegTC = 1;                     await DataBaseMethods.AddOrUpdateUser(                         callbackQuery.Message.Chat.Id,                         callbackQuery.Data.ToString(),                         callbackQuery.From.Username,                         callbackQuery.Message.From.Id,                         StageRegTC);                      await DataBaseMethods.AddTc(                         callbackQuery.Message.Chat.Id);                 } // начало регистрации Диспетчера                 if (callbackQuery.Data == "TcName")                 {                     await DataBaseMethods.StageIncrement(callbackQuery.Message.Chat.Id, 1);                     await botClient.SendTextMessageAsync(                         callbackQuery.Message.Chat.Id,                         text: "Введите ФИО:");                 }                 if (callbackQuery.Data == "FinReg")                 {                     await DataBaseMethods.StageIncrement(callbackQuery.Message.Chat.Id, 5);                     await botClient.SendTextMessageAsync(                         callbackQuery.Message.Chat.Id,                         text: "Регистрация окончена",                         replyMarkup: kb.ToMenu);                 } // общее окончание Регистрации             }         }         public static async Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken)         {             // Некоторые действия             Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(exception));         }         static void Main(string[] args)         {              Console.WriteLine("Запущен бот " + bot.GetMeAsync().Result.FirstName);             var cts = new CancellationTokenSource();             var cancellationToken = cts.Token;             var receiverOptions = new ReceiverOptions             {                 AllowedUpdates = { }, // receive all update types             };             bot.StartReceiving(                 HandleUpdateAsync,                 HandleErrorAsync,                 receiverOptions,                 cancellationToken             );             Console.ReadLine();                      }     } } 

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

Всем хорошего дня!


ссылка на оригинал статьи https://habr.com/ru/articles/699550/