Разработка ботов для Telegram стала неотъемлемой частью современной экосистемы мессенджеров. C# предоставляет мощный и удобный инструментарий для создания разнообразных ботов, от простых чат-помощников до сложных автоматизированных систем управления.
Telegram Bot API представляет собой интерфейс, позволяющий разработчикам создавать программы, которые взаимодействуют с Telegram от имени специальных аккаунтов — ботов. Эти боты могут обрабатывать сообщения, отправлять медиафайлы, создавать опросы, управлять группами и выполнять множество других задач.
Для разработки ботов на C# существует несколько популярных библиотек, которые значительно упрощают работу с Telegram Bot API. Они предоставляют удобные абстракции и инструменты для обработки сообщений, управления состоянием бота и взаимодействия с пользователями.
Основные преимущества использования C# для разработки Telegram ботов включают:
- Строгую типизацию, которая помогает избежать ошибок на этапе компиляции
- Богатую экосистему библиотек и инструментов
- Отличную производительность и масштабируемость
- Удобную асинхронную модель программирования
- Интеграцию с популярными средами разработки
При создании бота на C# разработчик получает доступ ко всем возможностям Telegram Bot API, включая:
- Отправку и получение текстовых сообщений
- Работу с медиафайлами (фото, видео, документы)
- Создание и обработку inline-кнопок и клавиатур
- Управление группами и каналами
- Обработку платежей
- Создание игр и интерактивных элементов
Архитектура типичного Telegram бота на C# обычно включает несколько ключевых компонентов: обработчик обновлений, который получает входящие сообщения и события, систему маршрутизации команд, которая направляет запросы к соответствующим обработчикам, и бизнес-логику, реализующую конкретные функции бота.
Важным аспектом разработки является правильная обработка исключений и реализация механизмов восстановления после сбоев, что обеспечивает надежную работу бота в производственной среде. Также следует уделить внимание логированию и мониторингу для отслеживания работоспособности бота и выявления потенциальных проблем.
В последующих разделах мы подробно рассмотрим процесс создания различных типов ботов, начиная с базовой настройки среды разработки и заканчивая развертыванием готового решения. Каждый пример будет сопровождаться практическим кодом и объяснением ключевых концепций.
Подготовка среды разработки
Для успешной разработки Telegram ботов на C# необходимо правильно настроить рабочее окружение. Начнем с установки необходимых инструментов и создания базовой структуры проекта.
Установка необходимых инструментов
Прежде всего, потребуется установить .NET SDK актуальной версии. Рекомендуется использовать .NET 6.0 или выше, так как эти версии обеспечивают лучшую производительность и имеют долгосрочную поддержку. После установки SDK убедитесь, что система правильно распознает его, выполнив команду "dotnet --version" в командной строке.
Для разработки понадобится современная IDE. Visual Studio или Visual Studio Code являются отличным выбором, так как они предоставляют богатый набор инструментов для работы с C# проектами. Visual Studio Community Edition бесплатна для индивидуальных разработчиков и небольших команд.
Создание базовой структуры проекта
Создайте новый проект консольного приложения .NET с помощью команды:
C# | 1
| dotnet new console -n TelegramBot |
|
Структура проекта должна включать следующие основные каталоги:
- /Services - для размещения сервисов бота
- /Models - для классов моделей данных
- /Handlers - для обработчиков команд
- /Configuration - для файлов конфигурации
- /Helpers - для вспомогательных классов
Подключение библиотек
Основной библиотекой для работы с Telegram Bot API является Telegram.Bot. Установите её через NuGet Package Manager или с помощью команды:
C# | 1
| dotnet add package Telegram.Bot |
|
Дополнительно рекомендуется установить следующие пакеты:
C# | 1
2
3
| dotnet add package Microsoft.Extensions.Hosting
dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.Json |
|
Настройка конфигурации
Создайте файл appsettings.json для хранения настроек бота:
C# | 1
2
3
4
5
6
| {
"BotConfiguration": {
"BotToken": "YOUR_BOT_TOKEN_HERE",
"ApiUrl": "https://api.telegram.org"
}
} |
|
Для работы с конфигурацией создайте класс:
C# | 1
2
3
4
5
| public class BotConfiguration
{
public string BotToken { get; set; }
public string ApiUrl { get; set; }
} |
|
Базовая структура программы
Создайте основной класс бота:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| public class Bot
{
private readonly ITelegramBotClient _botClient;
public Bot(BotConfiguration config)
{
_botClient = new TelegramBotClient(config.BotToken);
}
public async Task StartAsync()
{
var me = await _botClient.GetMeAsync();
Console.WriteLine($"Бот {me.Username} запущен");
}
} |
|
Организация обработки сообщений
Создайте базовый обработчик сообщений:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| public class UpdateHandler
{
private readonly ITelegramBotClient _botClient;
public UpdateHandler(ITelegramBotClient botClient)
{
_botClient = botClient;
}
public async Task HandleUpdateAsync(Update update, CancellationToken cancellationToken)
{
if (update.Message is not { } message)
return;
// Здесь будет логика обработки сообщений
}
} |
|
Такая структура проекта обеспечивает хорошую масштабируемость и поддерживаемость кода. Она позволяет легко добавлять новые функции и модифицировать существующие без необходимости существенных изменений в архитектуре приложения.
После настройки базовой структуры проекта можно приступать к реализации конкретных функций бота. Правильно организованная среда разработки значительно упрощает процесс создания и тестирования бота, а также облегчает дальнейшую поддержку проекта.
Базовые концепции
Для успешной разработки Telegram ботов важно понимать основные концепции и принципы их работы. Рассмотрим ключевые аспекты создания ботов на C#.
Жизненный цикл бота
Жизненный цикл Telegram бота начинается с его инициализации и установки соединения с серверами Telegram. Основные этапы включают:
1. Инициализация клиента:
C# | 1
| var botClient = new TelegramBotClient("YOUR_BOT_TOKEN"); |
|
2. Настройка обработчиков событий:
C# | 1
2
3
4
5
6
7
8
9
| var updateHandler = new UpdateHandler();
var receiverOptions = new ReceiverOptions
{
AllowedUpdates = new[] {
UpdateType.Message,
UpdateType.CallbackQuery,
UpdateType.InlineQuery
}
}; |
|
3. Запуск приема обновлений:
C# | 1
2
3
4
5
6
| await botClient.ReceiveAsync(
updateHandler.HandleUpdateAsync,
updateHandler.HandleErrorAsync,
receiverOptions,
cancellationToken
); |
|
Бот может работать в двух режимах получения обновлений:
- Long polling - постоянные запросы к серверу для получения новых сообщений
- Webhook - получение обновлений через HTTP callbacks
Обработка сообщений
Система обработки сообщений является центральной частью любого бота. Основные компоненты включают:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| public async Task HandleUpdateAsync(Update update, CancellationToken cancellationToken)
{
try
{
switch (update.Type)
{
case UpdateType.Message:
await HandleMessageAsync(update.Message);
break;
case UpdateType.CallbackQuery:
await HandleCallbackQueryAsync(update.CallbackQuery);
break;
case UpdateType.InlineQuery:
await HandleInlineQueryAsync(update.InlineQuery);
break;
}
}
catch (Exception ex)
{
await HandleErrorAsync(ex);
}
} |
|
Различные типы сообщений требуют разных подходов к обработке:
1. Текстовые сообщения:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
| private async Task HandleTextMessage(Message message)
{
var text = message.Text;
var chatId = message.Chat.Id;
if (text.StartsWith("/"))
{
await HandleCommand(message);
return;
}
await ProcessRegularMessage(message);
} |
|
2. Медиафайлы:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
| private async Task HandleMediaMessage(Message message)
{
var fileId = message.Photo?.LastOrDefault()?.FileId
?? message.Document?.FileId
?? message.Video?.FileId;
if (fileId != null)
{
var file = await _botClient.GetFileAsync(fileId);
await ProcessFile(file);
}
} |
|
3. Callback-запросы:
C# | 1
2
3
4
5
6
7
8
| private async Task HandleCallbackQuery(CallbackQuery callbackQuery)
{
var data = callbackQuery.Data;
var messageId = callbackQuery.Message.MessageId;
await ProcessCallback(data, messageId);
await _botClient.AnswerCallbackQueryAsync(callbackQuery.Id);
} |
|
Состояния и контексты
Для управления диалогами с пользователями важно реализовать систему состояний:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| public class UserState
{
public long ChatId { get; set; }
public string CurrentState { get; set; }
public Dictionary<string, object> Context { get; set; }
}
public class StateManager
{
private readonly Dictionary<long, UserState> _userStates;
public void SetState(long chatId, string state)
{
if (!_userStates.ContainsKey(chatId))
_userStates[chatId] = new UserState { ChatId = chatId };
_userStates[chatId].CurrentState = state;
}
public string GetState(long chatId)
{
return _userStates.TryGetValue(chatId, out var state)
? state.CurrentState
: "default";
}
} |
|
Клавиатуры и кнопки
Telegram предоставляет два типа клавиатур:
1. Обычная клавиатура:
C# | 1
2
3
4
5
6
7
8
9
| var replyKeyboard = new ReplyKeyboardMarkup(
new[]
{
new[] { new KeyboardButton("Опция 1"), new KeyboardButton("Опция 2") },
new[] { new KeyboardButton("Опция 3"), new KeyboardButton("Опция 4") }
})
{
ResizeKeyboard = true
}; |
|
2. Inline-клавиатура:
C# | 1
2
3
4
5
6
7
8
9
| var inlineKeyboard = new InlineKeyboardMarkup(
new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData("Кнопка 1", "action1"),
InlineKeyboardButton.WithCallbackData("Кнопка 2", "action2")
}
}); |
|
Обработка ошибок
Реализация надежной системы обработки ошибок критически важна:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| public async Task HandleErrorAsync(Exception exception, CancellationToken cancellationToken)
{
var ErrorMessage = exception switch
{
ApiRequestException apiRequestException
=> $"Telegram API Error:\n{apiRequestException.ErrorCode}\n{apiRequestException.Message}",
_ => exception.ToString()
};
await LogError(ErrorMessage);
if (exception is ApiRequestException apiException && apiException.ErrorCode == 429)
{
// Обработка превышения лимита запросов
await HandleRateLimiting(apiException);
}
} |
|
Работа с командами
Реализация обработки команд является важной частью функциональности бота. Рассмотрим основные подходы к организации командной системы:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| public class CommandHandler
{
private readonly Dictionary<string, Func<Message, Task>> _commands;
public CommandHandler()
{
_commands = new Dictionary<string, Func<Message, Task>>
{
{ "/start", HandleStartCommand },
{ "/help", HandleHelpCommand },
{ "/settings", HandleSettingsCommand }
};
}
public async Task HandleCommand(Message message)
{
var command = message.Text.Split(' ')[0].ToLower();
if (_commands.TryGetValue(command, out var handler))
{
await handler(message);
}
}
} |
|
Для более сложных команд можно использовать атрибуты и рефлексию:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| [AttributeUsage(AttributeTargets.Method)]
public class BotCommandAttribute : Attribute
{
public string Command { get; }
public string Description { get; }
public BotCommandAttribute(string command, string description)
{
Command = command;
Description = description;
}
}
public class CommandService
{
[BotCommand("start", "Начать работу с ботом")]
public async Task StartCommand(Message message)
{
// Логика обработки команды start
}
[BotCommand("help", "Показать справку")]
public async Task HelpCommand(Message message)
{
// Логика обработки команды help
}
} |
|
Middleware и фильтры
Для обработки сообщений до их попадания в основные обработчики можно использовать систему middleware:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| public interface IUpdateMiddleware
{
Task HandleAsync(Update update, UpdateDelegate next);
}
public class LoggingMiddleware : IUpdateMiddleware
{
public async Task HandleAsync(Update update, UpdateDelegate next)
{
Console.WriteLine($"Получено обновление типа: {update.Type}");
await next(update);
Console.WriteLine("Обработка завершена");
}
}
public class AuthenticationMiddleware : IUpdateMiddleware
{
public async Task HandleAsync(Update update, UpdateDelegate next)
{
if (IsAuthorized(update))
{
await next(update);
}
else
{
// Отправка сообщения о необходимости авторизации
}
}
} |
|
Работа с контекстом
Для сохранения контекста диалога между сообщениями можно использовать следующий подход:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| public class ConversationContext
{
private readonly Dictionary<long, Stack<string>> _contextStack;
public void PushContext(long chatId, string context)
{
if (!_contextStack.ContainsKey(chatId))
_contextStack[chatId] = new Stack<string>();
_contextStack[chatId].Push(context);
}
public string PopContext(long chatId)
{
if (_contextStack.TryGetValue(chatId, out var stack) && stack.Count > 0)
return stack.Pop();
return null;
}
public string PeekContext(long chatId)
{
if (_contextStack.TryGetValue(chatId, out var stack) && stack.Count > 0)
return stack.Peek();
return null;
}
} |
|
Это позволяет создавать сложные диалоговые сценарии и сохранять состояние разговора с пользователем между сообщениями. Контекст особенно полезен при реализации многошаговых операций, таких как регистрация или настройка параметров.
Примеры телеграм ботов на C#
Рассмотрим реализацию наиболее популярных типов Telegram ботов на C#. Начнем с простых примеров и постепенно перейдем к более сложным реализациям.
Эхо-бот с базовыми командами
Простейший эхо-бот является отличной отправной точкой для понимания основ работы с Telegram Bot API:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| public class EchoBot
{
private readonly ITelegramBotClient _botClient;
public async Task HandleUpdateAsync(Update update, CancellationToken ct)
{
if (update.Message?.Text == null)
return;
var message = update.Message;
var chatId = message.Chat.Id;
await _botClient.SendTextMessageAsync(
chatId: chatId,
text: $"Вы написали: {message.Text}",
cancellationToken: ct
);
}
} |
|
Бот погоды с API интеграцией
Погодный бот демонстрирует работу с внешними API и форматирование ответов:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| public class WeatherBot
{
private readonly IWeatherService _weatherService;
private readonly ITelegramBotClient _botClient;
public async Task HandleWeatherRequest(Message message)
{
var location = message.Text;
var weatherInfo = await _weatherService.GetWeatherAsync(location);
var response = $"Погода в {location}:\n" +
$"Температура: {weatherInfo.Temperature}°C\n" +
$"Влажность: {weatherInfo.Humidity}%\n" +
$"Ветер: {weatherInfo.WindSpeed} м/с";
await _botClient.SendTextMessageAsync(
message.Chat.Id,
response,
replyMarkup: GetWeatherKeyboard()
);
}
} |
|
Бот-переводчик
Бот-переводчик показывает работу с текстовыми сервисами и inline-клавиатурами:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| public class TranslatorBot
{
private readonly ITranslationService _translationService;
public async Task HandleTranslation(Message message)
{
var text = message.Text;
var keyboard = new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData("EN → RU", $"translate_en_ru_{text}"),
InlineKeyboardButton.WithCallbackData("RU → EN", $"translate_ru_en_{text}")
}
});
await _botClient.SendTextMessageAsync(
message.Chat.Id,
"Выберите направление перевода:",
replyMarkup: keyboard
);
}
} |
|
Бот для напоминаний и планировщик
Планировщик задач демонстрирует работу с базой данных и временными задачами:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| public class ReminderBot
{
private readonly ISchedulerService _scheduler;
private readonly IDatabase _database;
public async Task AddReminder(Message message, string time, string text)
{
var reminder = new Reminder
{
ChatId = message.Chat.Id,
Time = DateTime.Parse(time),
Text = text
};
await _database.SaveReminderAsync(reminder);
await _scheduler.ScheduleReminderAsync(reminder);
await _botClient.SendTextMessageAsync(
message.Chat.Id,
$"Напоминание установлено на {time}"
);
}
} |
|
Игра "Крестики-нолики"
Пример простой игры "Крестики-нолики" показывает работу с интерактивными элементами:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| public class TicTacToeBot
{
private readonly Dictionary<long, GameState> _games = new();
public async Task HandleMove(CallbackQuery query)
{
var gameState = _games[query.Message.Chat.Id];
var position = int.Parse(query.Data.Split('_')[1]);
if (gameState.MakeMove(position))
{
var keyboard = GenerateGameBoard(gameState);
await _botClient.EditMessageReplyMarkupAsync(
query.Message.Chat.Id,
query.Message.MessageId,
keyboard
);
}
}
private InlineKeyboardMarkup GenerateGameBoard(GameState state)
{
var buttons = new List<InlineKeyboardButton[]>();
for (int i = 0; i < 3; i++)
{
var row = new InlineKeyboardButton[3];
for (int j = 0; j < 3; j++)
{
var position = i * 3 + j;
var symbol = state.GetSymbol(position);
row[j] = InlineKeyboardButton.WithCallbackData(
symbol.ToString(),
$"move_{position}"
);
}
buttons.Add(row);
}
return new InlineKeyboardMarkup(buttons);
}
} |
|
Бот для модерации группы
Модерационный бот демонстрирует работу с правами администратора и фильтрацией контента:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| public class ModerationBot
{
private readonly IContentFilter _contentFilter;
public async Task HandleNewMessage(Message message)
{
if (await _contentFilter.ContainsSpam(message.Text))
{
await _botClient.DeleteMessageAsync(
message.Chat.Id,
message.MessageId
);
await _botClient.RestrictChatMemberAsync(
message.Chat.Id,
message.From.Id,
new ChatPermissions { CanSendMessages = false },
untilDate: DateTime.UtcNow.AddMinutes(30)
);
await _botClient.SendTextMessageAsync(
message.Chat.Id,
$"Пользователь {message.From.FirstName} заблокирован на 30 минут за спам"
);
}
}
} |
|
Каждый из этих примеров может быть расширен дополнительной функциональностью и адаптирован под конкретные требования. Важно помнить о правильной обработке ошибок и ограничениях API при реализации любого из этих ботов.
Бот для опросов и голосований
Создание опросов и голосований - важная функция для групповых чатов:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| public class PollBot
{
private readonly Dictionary<string, Poll> _activePolls = new();
public async Task CreatePoll(Message message)
{
var pollOptions = message.Text.Split('\n').Skip(1).ToArray();
var poll = await _botClient.SendPollAsync(
chatId: message.Chat.Id,
question: pollOptions[0],
options: pollOptions.Skip(1).ToArray(),
isAnonymous: false,
allowsMultipleAnswers: false
);
_activePolls[poll.Poll.Id] = new Poll
{
CreatorId = message.From.Id,
Options = pollOptions
};
}
} |
|
Новостной агрегатор
Бот для сбора и отправки новостей демонстрирует работу с RSS-лентами и периодическими задачами:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| public class NewsBot
{
private readonly INewsService _newsService;
private readonly ISubscriptionManager _subscriptionManager;
public async Task HandleSubscription(Message message)
{
var chatId = message.Chat.Id;
var categories = await _newsService.GetAvailableCategories();
var keyboard = new InlineKeyboardMarkup(
categories.Select(c => new[]
{
InlineKeyboardButton.WithCallbackData(
c.Name,
$"subscribe_{c.Id}"
)
})
);
await _botClient.SendTextMessageAsync(
chatId,
"Выберите категории новостей:",
replyMarkup: keyboard
);
}
public async Task SendNewsUpdate()
{
var subscriptions = await _subscriptionManager.GetAllSubscriptions();
foreach (var sub in subscriptions)
{
var news = await _newsService.GetLatestNews(sub.Categories);
foreach (var item in news)
{
await _botClient.SendTextMessageAsync(
sub.ChatId,
$"*{item.Title}*\n\n{item.Summary}",
parseMode: ParseMode.Markdown
);
}
}
}
} |
|
Файловый менеджер
Телеграм бот на C# для работы с файлами показывает обработку различных типов документов:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| public class FileManagerBot
{
private readonly IFileStorage _storage;
public async Task HandleFileUpload(Message message)
{
var file = message.Document;
if (file != null)
{
var fileInfo = await _botClient.GetFileAsync(file.FileId);
var fileName = file.FileName;
await using var stream = new MemoryStream();
await _botClient.DownloadFileAsync(fileInfo.FilePath, stream);
var fileUrl = await _storage.UploadFile(stream, fileName);
await _botClient.SendTextMessageAsync(
message.Chat.Id,
$"Файл сохранен. Используйте команду /get_{fileName} для доступа"
);
}
}
public async Task HandleFileRequest(Message message)
{
var fileName = message.Text.Replace("/get_", "");
var fileStream = await _storage.GetFile(fileName);
await _botClient.SendDocumentAsync(
message.Chat.Id,
new InputFileStream(fileStream, fileName)
);
}
} |
|
Конвертер валют
Бот для конвертации валют демонстрирует работу с внешними API и кэшированием данных:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| public class CurrencyBot
{
private readonly ICurrencyService _currencyService;
private readonly IMemoryCache _cache;
public async Task HandleConversion(Message message)
{
var parts = message.Text.Split(' ');
if (parts.Length == 4)
{
var amount = decimal.Parse(parts[1]);
var fromCurrency = parts[2].ToUpper();
var toCurrency = parts[3].ToUpper();
var rate = await GetExchangeRate(fromCurrency, toCurrency);
var result = amount * rate;
await _botClient.SendTextMessageAsync(
message.Chat.Id,
$"{amount} {fromCurrency} = {result:F2} {toCurrency}"
);
}
}
private async Task<decimal> GetExchangeRate(string from, string to)
{
var cacheKey = $"{from}_{to}";
if (!_cache.TryGetValue(cacheKey, out decimal rate))
{
rate = await _currencyService.GetExchangeRate(from, to);
_cache.Set(cacheKey, rate, TimeSpan.FromHours(1));
}
return rate;
}
} |
|
Бот-администратор канала
Этот бот помогает управлять контентом и пользователями в каналах:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
| public class ChannelAdminBot
{
private readonly IContentScheduler _scheduler;
public async Task SchedulePost(Message message)
{
var content = message.Text;
var keyboard = new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData("Опубликовать сейчас", "publish_now"),
InlineKeyboardButton.WithCallbackData("Запланировать", "schedule")
}
});
await _botClient.SendTextMessageAsync(
message.Chat.Id,
"Выберите действие:",
replyMarkup: keyboard
);
await _scheduler.SaveDraft(message.Chat.Id, content);
}
public async Task HandleScheduling(CallbackQuery query)
{
var content = await _scheduler.GetDraft(query.Message.Chat.Id);
if (query.Data == "publish_now")
{
await _botClient.SendTextMessageAsync(
"@channel_name",
content
);
}
else
{
// Показать календарь для выбора времени публикации
await ShowScheduleCalendar(query.Message.Chat.Id);
}
}
} |
|
Бот проигрыватель музыки
Музыкальный бот может обрабатывать аудиофайлы и предоставлять информацию о музыке:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| public class MusicBot
{
private readonly IMusicService _musicService;
private readonly IAudioProcessor _audioProcessor;
public async Task HandleAudioMessage(Message message)
{
var audio = message.Audio;
if (audio != null)
{
var metadata = await _musicService.GetMetadata(audio);
await _botClient.SendTextMessageAsync(
message.Chat.Id,
$"Трек: {metadata.Title}\n" +
$"Исполнитель: {metadata.Artist}\n" +
$"Альбом: {metadata.Album}\n" +
$"Год: {metadata.Year}"
);
}
}
public async Task HandleMusicSearch(Message message)
{
var query = message.Text.Replace("/search ", "");
var results = await _musicService.SearchTracks(query);
var keyboard = new InlineKeyboardMarkup(
results.Select(r => new[]
{
InlineKeyboardButton.WithCallbackData(
$"{r.Artist} - {r.Title}",
$"play_{r.Id}"
)
})
);
await _botClient.SendTextMessageAsync(
message.Chat.Id,
"Найденные треки:",
replyMarkup: keyboard
);
}
} |
|
Бот для заметок
Бот для создания и управления заметками демонстрирует работу с пользовательскими данными:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| public class NotesBot
{
private readonly INotesRepository _repository;
public async Task HandleNewNote(Message message)
{
var note = new Note
{
UserId = message.From.Id,
Content = message.Text,
CreatedAt = DateTime.UtcNow
};
await _repository.SaveNote(note);
await _botClient.SendTextMessageAsync(
message.Chat.Id,
"Заметка сохранена! Используйте /list для просмотра всех заметок"
);
}
public async Task ListNotes(Message message)
{
var notes = await _repository.GetUserNotes(message.From.Id);
var notesList = notes.Select((n, i) =>
$"{i + 1}. {n.Content.Substring(0, Math.Min(50, n.Content.Length))}..."
);
var response = string.Join("\n", notesList);
await _botClient.SendTextMessageAsync(
message.Chat.Id,
response.Length > 0 ? response : "У вас пока нет заметок"
);
}
} |
|
Календарь событий
Бот-календарь помогает управлять событиями и встречами:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| public class CalendarBot
{
private readonly IEventManager _eventManager;
public async Task AddEvent(Message message)
{
var eventData = message.Text.Split('\n');
var newEvent = new Event
{
Title = eventData[0],
Description = eventData[1],
DateTime = DateTime.Parse(eventData[2]),
UserId = message.From.Id
};
await _eventManager.CreateEvent(newEvent);
var reminderKeyboard = new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData("За 1 час", $"remind_1h_{newEvent.Id}"),
InlineKeyboardButton.WithCallbackData("За 1 день", $"remind_1d_{newEvent.Id}")
}
});
await _botClient.SendTextMessageAsync(
message.Chat.Id,
"Событие добавлено! Настроить напоминание?",
replyMarkup: reminderKeyboard
);
}
public async Task ViewCalendar(Message message)
{
var events = await _eventManager.GetUserEvents(message.From.Id);
var calendar = GenerateCalendarView(events);
await _botClient.SendTextMessageAsync(
message.Chat.Id,
calendar,
parseMode: ParseMode.Markdown
);
}
} |
|
Статистика и аналитика
Бот для сбора и анализа статистики показывает работу с данными и визуализацией:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
| public class AnalyticsBot
{
private readonly IStatisticsService _statisticsService;
private readonly IChartGenerator _chartGenerator;
public async Task GenerateReport(Message message)
{
var stats = await _statisticsService.GetGroupStats(message.Chat.Id);
var chartImage = await _chartGenerator.CreateChart(stats);
var report = $"Статистика за период:\n" +
$"Всего сообщений: {stats.MessageCount}\n" +
$"Активных пользователей: {stats.ActiveUsers}\n" +
$"Популярные темы: {string.Join(", ", stats.TopTopics)}";
await _botClient.SendPhotoAsync(
message.Chat.Id,
new InputFileStream(chartImage, "statistics.png"),
caption: report
);
}
public async Task TrackActivity(Message message)
{
await _statisticsService.LogActivity(new ActivityLog
{
ChatId = message.Chat.Id,
UserId = message.From.Id,
MessageType = message.Type,
Timestamp = DateTime.UtcNow
});
}
public async Task GenerateUserReport(Message message)
{
var userData = await _statisticsService.GetUserStats(message.From.Id);
var userChart = await _chartGenerator.CreateUserActivityChart(userData);
var userReport = $"Ваша активность:\n" +
$"Отправлено сообщений: {userData.SentMessages}\n" +
$"Среднее количество сообщений в день: {userData.AveragePerDay}\n" +
$"Самое активное время: {userData.PeakHour:HH:mm}";
await _botClient.SendPhotoAsync(
message.Chat.Id,
new InputFileStream(userChart, "user_stats.png"),
caption: userReport
);
}
} |
|
Лучшие практики и оптимизация
При разработке Telegram ботов важно следовать определенным практикам и принципам оптимизации для обеспечения надежной и эффективной работы. Рассмотрим основные рекомендации.
Архитектурные принципы
Следуйте принципу разделения ответственности (SRP) при проектировании бота. Выделяйте отдельные компоненты для различных функций:
- Обработка обновлений
- Бизнес-логика
- Доступ к данным
- Внешние интеграции
Используйте внедрение зависимостей для улучшения тестируемости и поддерживаемости кода:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
| public class Bot
{
private readonly ITelegramBotClient _botClient;
private readonly ILogger _logger;
private readonly IUpdateHandler _updateHandler;
public Bot(ITelegramBotClient botClient, ILogger logger, IUpdateHandler updateHandler)
{
_botClient = botClient;
_logger = logger;
_updateHandler = updateHandler;
}
} |
|
Оптимизация производительности
Используйте асинхронные операции везде, где это возможно, чтобы избежать блокировки потоков:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| public async Task ProcessUpdatesAsync(IEnumerable<Update> updates)
{
var tasks = updates.Select(async update =>
{
try
{
await _updateHandler.HandleUpdateAsync(update);
}
catch (Exception ex)
{
await _logger.LogErrorAsync(ex);
}
});
await Task.WhenAll(tasks);
} |
|
Реализуйте кэширование для часто запрашиваемых данных:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
| public class CacheService
{
private readonly IMemoryCache _cache;
public async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> factory)
{
if (!_cache.TryGetValue(key, out T value))
{
value = await factory();
_cache.Set(key, value, TimeSpan.FromMinutes(30));
}
return value;
}
} |
|
Обработка ошибок
Реализуйте централизованную систему обработки исключений:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| public class ErrorHandler
{
private readonly ILogger _logger;
public async Task HandleErrorAsync(Exception exception, CancellationToken ct)
{
var errorMessage = exception switch
{
ApiRequestException apiRequestException =>
$"Telegram API Error: {apiRequestException.ErrorCode}",
TaskCanceledException => "Request timed out",
_ => "An error occurred"
};
await _logger.LogErrorAsync(errorMessage, exception);
}
} |
|
Мониторинг и логирование
Внедрите систему мониторинга для отслеживания производительности и состояния бота:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
| public class BotMetrics
{
private readonly IMetricsCollector _metrics;
public async Task TrackUpdate(Update update)
{
_metrics.IncrementCounter("bot.updates.total");
_metrics.RecordTiming("bot.processing.time", async () =>
{
await ProcessUpdate(update);
});
}
} |
|
Используйте структурированное логирование для упрощения анализа проблем:
C# | 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| public class LoggingService
{
public async Task LogMessage(LogLevel level, string message, Dictionary<string, object> properties)
{
var logEntry = new LogEntry
{
Level = level,
Message = message,
Properties = properties,
Timestamp = DateTime.UtcNow
};
await WriteLogAsync(logEntry);
}
} |
|
Безопасность
Применяйте следующие практики безопасности:
- Храните токены и секреты в защищенном хранилище
- Проверяйте входящие данные на валидность
- Ограничивайте доступ к административным функциям
- Используйте HTTPS для внешних запросов
- Регулярно обновляйте зависимости
Масштабирование
Проектируйте бота с учетом возможности горизонтального масштабирования:
- Используйте очереди сообщений
- Храните состояние в распределенном хранилище
- Применяйте балансировку нагрузки
- Реализуйте механизмы восстановления после сбоев
Развертывание и поддержка
Успешное развертывание и поддержка Telegram бота требуют внимательного подхода к нескольким ключевым аспектам. Рассмотрим основные рекомендации для обеспечения стабильной работы вашего бота.
При выборе хостинга следует учитывать требования к производительности и масштабируемости. Для небольших ботов подойдут облачные платформы с поддержкой .NET, такие как Azure App Service или AWS Elastic Beanstalk. Более сложные боты могут потребовать развертывания в контейнерах с использованием Docker и оркестрации через Kubernetes.
Настройка мониторинга является критически важным этапом. Внедрите систему оповещений для отслеживания:
- Времени отклика бота
- Количества обрабатываемых сообщений
- Использования ресурсов сервера
- Ошибок и исключений
Регулярное резервное копирование данных поможет быстро восстановить работу бота в случае сбоев. Автоматизируйте процесс создания резервных копий и периодически проверяйте возможность восстановления из них.
Для обеспечения непрерывной работы реализуйте автоматическое масштабирование и балансировку нагрузки. Это особенно важно для ботов с большим количеством пользователей или интенсивной обработкой данных.
Обновление бота должно проходить по четкому плану:
- Тестирование изменений в отдельной среде
- Постепенное развертывание обновлений
- Наличие плана отката изменений
- Минимизация времени простоя
Поддерживайте актуальную документацию по настройке, развертыванию и устранению неисправностей. Это упростит поддержку бота и передачу знаний между членами команды разработки.
Регулярно проверяйте и обновляйте зависимости проекта для устранения потенциальных уязвимостей безопасности. Используйте инструменты анализа зависимостей для автоматического отслеживания обновлений. |