Skip to main content

Creating Handlers

Handlers are the core building blocks of your Telegrator bot. Each handler processes specific types of Telegram updates and encapsulates a discrete piece of bot functionality.

Handler Types

Telegrator provides several handler base classes for different update types:
  • MessageHandler - Processes message updates
  • CommandHandler - Processes command messages (e.g., /start)
  • CallbackQueryHandler - Processes inline keyboard button clicks
  • AnyUpdateHandler - Processes any type of update

Creating a Message Handler

1

Create a handler class

Inherit from MessageHandler and decorate with [MessageHandler] attribute:
using Telegrator.Handlers;
using Telegrator.Annotations;
using Telegram.Bot.Types;

[MessageHandler]
public class HelloHandler : MessageHandler
{
    public override async Task<Result> Execute(
        IHandlerContainer<Message> container, 
        CancellationToken cancellation)
    {
        await Reply("Hello, world!", cancellationToken: cancellation);
        return Result.Ok();
    }
}
2

Register the handler

Add your handler to the bot’s handler collection:
var bot = new TelegratorClient("YOUR_BOT_TOKEN");
bot.Handlers.AddHandler<HelloHandler>();
bot.StartReceiving();

Accessing Update Data

Inside your handler, you have convenient properties to access update information:
[MessageHandler]
public class EchoHandler : MessageHandler
{
    public override async Task<Result> Execute(
        IHandlerContainer<Message> container, 
        CancellationToken cancellation)
    {
        // Access the incoming message
        var messageText = Input.Text;
        
        // Access the Telegram Bot client
        await Client.SendTextMessageAsync(
            Input.Chat.Id,
            $"You said: {messageText}",
            cancellationToken: cancellation);
        
        // Or use the convenient Reply method
        await Reply($"Echo: {messageText}", cancellationToken: cancellation);
        
        return Result.Ok();
    }
}

Creating a Command Handler

Command handlers process messages that start with / (e.g., /start, /help).
1

Create command handler class

Inherit from CommandHandler and use [CommandHandler] with [CommandAllias]:
using Telegrator.Handlers;
using Telegrator.Annotations;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;

[CommandHandler]
[CommandAllias("start", "hello")]
[ChatType(ChatType.Private)]
public class StartCommandHandler : CommandHandler
{
    public override async Task<Result> Execute(
        IHandlerContainer<Message> container,
        CancellationToken cancellation)
    {
        await Response(
            "Welcome to the bot! Use /help to see available commands.",
            cancellationToken: cancellation);
        
        return Result.Ok();
    }
}
2

Access command arguments

Command handlers provide properties to access command arguments:
[CommandHandler]
[CommandAllias("greet")]
public class GreetCommandHandler : CommandHandler
{
    public override async Task<Result> Execute(
        IHandlerContainer<Message> container,
        CancellationToken cancellation)
    {
        // Get command arguments as array
        string[] args = Arguments;
        
        // Get full arguments string
        string argsString = ArgumentsString;
        
        // Get the command that was used
        string command = ReceivedCommand;
        
        if (args.Length > 0)
        {
            await Reply($"Hello, {args[0]}!", cancellationToken: cancellation);
        }
        else
        {
            await Reply("Hello! Please provide a name.", cancellationToken: cancellation);
        }
        
        return Result.Ok();
    }
}
The ReceivedCommand property returns the command without the / prefix and bot username. For example, /start@mybot returns "start".

Creating a Callback Query Handler

Callback query handlers process button clicks from inline keyboards.
using Telegrator.Handlers;
using Telegrator.Annotations;
using Telegram.Bot.Types;
using Telegram.Bot.Types.ReplyMarkups;

[CallbackQueryHandler]
[CallbackDataRegex(@"^button_\\d+$")]
public class ButtonClickHandler : CallbackQueryHandler
{
    public override async Task<Result> Execute(
        IHandlerContainer<CallbackQuery> container,
        CancellationToken cancellation)
    {
        // Get the callback data
        string data = TypeData;
        
        // Answer the callback query (removes loading state)
        await Answer("Button clicked!", showAlert: false, cancellationToken: cancellation);
        
        // Edit the message that contained the button
        await EditMessage(
            $"You clicked: {data}",
            replyMarkup: new InlineKeyboardMarkup(
                InlineKeyboardButton.WithCallbackData("Click again", "button_1")
            ),
            cancellationToken: cancellation);
        
        return Result.Ok();
    }
}
[CommandHandler]
[CommandAllias("menu")]
public class MenuCommandHandler : CommandHandler
{
    public override async Task<Result> Execute(
        IHandlerContainer<Message> container,
        CancellationToken cancellation)
    {
        var keyboard = new InlineKeyboardMarkup(new[]
        {
            new[]
            {
                InlineKeyboardButton.WithCallbackData("Option 1", "button_1"),
                InlineKeyboardButton.WithCallbackData("Option 2", "button_2")
            },
            new[]
            {
                InlineKeyboardButton.WithCallbackData("Option 3", "button_3")
            }
        });
        
        await Reply("Choose an option:", replyMarkup: keyboard, cancellationToken: cancellation);
        return Result.Ok();
    }
}

Handler Priorities and Importance

Control the execution order of handlers using the Importance and Priority parameters:
// Higher importance handlers are checked first
[MessageHandler(importance: 10)]
[TextContains("admin")]
public class AdminMessageHandler : MessageHandler
{
    public override async Task<Result> Execute(
        IHandlerContainer<Message> container,
        CancellationToken cancellation)
    {
        await Reply("Admin command detected", cancellationToken: cancellation);
        return Result.Ok();
    }
}

// Lower importance, checked later
[MessageHandler(importance: 0)]
public class GeneralMessageHandler : MessageHandler
{
    public override async Task<Result> Execute(
        IHandlerContainer<Message> container,
        CancellationToken cancellation)
    {
        await Reply("General message", cancellationToken: cancellation);
        return Result.Ok();
    }
}
Handlers with higher importance values are evaluated first. If multiple handlers match an update, the one with the highest importance will execute. Use Priority to control the order among handlers with the same importance level.

Available Handler Properties

All handlers provide access to these properties:
PropertyTypeDescription
InputTUpdateThe incoming update object (Message, CallbackQuery, etc.)
ClientITelegramBotClientThe Telegram Bot API client
HandlingUpdateUpdateThe full Telegram update object
ExtraDataDictionary<string, object>Container for sharing data between filters and handlers
CompletedFiltersCompletedFiltersListList of filters that passed successfully
AwaitingProviderIAwaitingProviderProvider for awaiting subsequent updates

Next Steps

Working with Filters

Learn how to add filters to control when handlers execute

Managing State

Implement multi-step flows and wizards with state management

Build docs developers (and LLMs) love