Filters are attributes that declaratively specify which updates a handler should process. They provide a clean, readable way to validate updates before handler execution, reducing boilerplate code and improving maintainability.
[MessageHandler][TextEndsWith("?")]public class QuestionHandler : MessageHandler{ public override async Task<Result> Execute( IHandlerContainer<Message> container, CancellationToken cancellation) { await Reply("That's a great question! Let me think..."); return Result.Ok(); }}
[MessageHandler][TextContains("help", StringComparison.OrdinalIgnoreCase)]public class HelpKeywordHandler : MessageHandler{ public override async Task<Result> Execute( IHandlerContainer<Message> container, CancellationToken cancellation) { await Reply("It looks like you need help. Type /help for assistance."); return Result.Ok(); }}
Matches messages containing a specific word (not just substring):
[MessageHandler][TextContainsWord("urgent", StringComparison.OrdinalIgnoreCase)]public class UrgentHandler : MessageHandler{ public override async Task<Result> Execute( IHandlerContainer<Message> container, CancellationToken cancellation) { // Matches "This is urgent" but not "surgery" await Reply("⚠️ Urgent request received. Processing with priority."); return Result.Ok(); }}
TextContainsWord ensures the matched text is a separate word, not part of another word. It checks that there are no alphabetic characters adjacent to the match.
Matches messages from a user with specific first/last name:
// Match by first name only[MessageHandler][FromUser("John")]public class FirstNameHandler : MessageHandler { }// Match by first and last name[MessageHandler][FromUser("John", "Doe")]public class FullNameHandler : MessageHandler { }// With custom comparison[MessageHandler][FromUser("John", StringComparison.OrdinalIgnoreCase)]public class CaseInsensitiveHandler : MessageHandler { }
Filter messages based on whether the sender is a bot:
// Only process messages from bots[MessageHandler][FromBot]public class BotMessagesHandler : MessageHandler { }// Only process messages from humans[MessageHandler][NotFromBot]public class HumanMessagesHandler : MessageHandler { }
[CommandHandler][CommandAllias("search", Description = "Search for items in the database")]public class SearchHandler : CommandHandler{ // Description is used for generating bot command lists}
[MessageHandler][NumericState(1)] // Only when user is in state 1public class Step1Handler : MessageHandler{ public override async Task<Result> Execute( IHandlerContainer<Message> container, CancellationToken cancellation) { // Process step 1 Container.ForwardNumericState(); // Move to state 2 await Reply("Step 1 complete. Moving to step 2..."); return Result.Ok(); }}
[MessageHandler][StringState("awaiting_name")]public class NameInputHandler : MessageHandler{ public override async Task<Result> Execute( IHandlerContainer<Message> container, CancellationToken cancellation) { string name = Input.Text; // Save name Container.SetStringState("awaiting_age"); await Reply("Great! Now, how old are you?"); return Result.Ok(); }}
// Only in private chats[MessageHandler][PrivateChat]public class PrivateOnlyHandler : MessageHandler { }// Only in groups[MessageHandler][GroupChat]public class GroupOnlyHandler : MessageHandler { }// Only in supergroups[MessageHandler][SupergroupChat]public class SupergroupOnlyHandler : MessageHandler { }// Only in channels[MessageHandler][ChannelChat]public class ChannelOnlyHandler : MessageHandler { }
Filters receive a FilterExecutionContext<T> containing:
public class FilterExecutionContext<T>{ // Bot information public ITelegramBotInfo BotInfo { get; } // The input being filtered public T Input { get; } // The original update public Update Update { get; } // Custom data dictionary public Dictionary<string, object> Data { get; } // Completed filters public IReadOnlyList<object> CompletedFilters { get; }}