Filters determine when a handler should execute. Telegrator provides a rich filtering system that allows you to declaratively specify handler trigger conditions.
You can apply multiple filters to a handler - all filters must pass for the handler to execute:
[MessageHandler][ChatType(ChatType.Private)][TextContains("help")][SenderIsBot(false)]public class PrivateHelpHandler : MessageHandler{ public override async Task<Result> Execute( IHandlerContainer<Message> container, CancellationToken cancellation) { // This executes only if: // - Message is from a private chat // - Message contains "help" // - Sender is not a bot await Reply("How can I help you?", cancellationToken: cancellation); return Result.Ok(); }}
When multiple filters are applied, they use AND logic - all filters must pass.
For OR logic, create multiple handlers or use custom filters.
You can create custom filters by inheriting from Filter<T>:
using Telegrator.Filters;using Telegrator.Filters.Components;using Telegram.Bot.Types;// Custom filter that checks if message length exceeds a limitpublic class MessageLengthFilter : Filter<Message>{ private readonly int _maxLength; public int MaxLength => _maxLength; public MessageLengthFilter(int maxLength) { _maxLength = maxLength; } public override bool CanPass(FilterExecutionContext<Message> context) { return context.Input.Text?.Length <= _maxLength; }}
Create a custom attribute that implements IFilter<Update>:
using Telegrator.Filters.Components;using Telegram.Bot.Types;[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]public class MessageLengthAttribute : Attribute, IFilter<Update>{ private readonly int _maxLength; public bool IsCollectible => true; public int MaxLength => _maxLength; public MessageLengthAttribute(int maxLength) { _maxLength = maxLength; } public bool CanPass(FilterExecutionContext<Update> context) { if (context.Input.Message?.Text is not { } text) return false; return text.Length <= _maxLength; }}// Usage[MessageHandler][MessageLength(100)] // Only messages up to 100 characterspublic class ShortMessageHandler : MessageHandler{ public override async Task<Result> Execute( IHandlerContainer<Message> container, CancellationToken cancellation) { await Reply("Thanks for the short message!", cancellationToken: cancellation); return Result.Ok(); }}
You can create filters programmatically using the Filter<T>.If() method:
using Telegrator.Filters;using Telegram.Bot.Types;// Create a filter from a lambdavar isLongMessage = Filter<Message>.If(ctx => ctx.Input.Text?.Length > 100);// Use with handler builder (see Handler Builder guide)handlers.Message() .AddFilter(isLongMessage) .Build(async (container, cancellation) => { await container.Reply("That's a long message!", cancellationToken: cancellation); return Result.Ok(); });
Filters receive a FilterExecutionContext<T> that provides access to:
public class CustomContextFilter : Filter<Message>{ public override bool CanPass(FilterExecutionContext<Message> context) { // Access the input Message message = context.Input; // Access the bot client ITelegramBotClient client = context.Client; // Access the full update Update update = context.Update; // Access extra data dictionary (shared across filters) Dictionary<string, object> extraData = context.ExtraData; // Store data for the handler to use context.ExtraData["filterCheckTime"] = DateTime.UtcNow; return message.Text?.Length > 0; }}
Handlers can access data from filters that passed:
[MessageHandler][TextRegex(@"^\\d+$")]public class NumberHandler : MessageHandler{ public override async Task<Result> Execute( IHandlerContainer<Message> container, CancellationToken cancellation) { // Access filters that passed var textRegexFilter = CompletedFilters.Get<TextRegexAttribute>(0); // Access extra data set by filters if (ExtraData.TryGetValue("filterCheckTime", out var checkTime)) { var time = (DateTime)checkTime; // Use the data... } await Reply("Processing number...", cancellationToken: cancellation); return Result.Ok(); }}
[MessageHandler][Environment("Development", "Staging")]public class DebugHandler : MessageHandler{ public override async Task<Result> Execute( IHandlerContainer<Message> container, CancellationToken cancellation) { // This handler only runs in Development or Staging await Reply("Debug info: " + Input.Text, cancellationToken: cancellation); return Result.Ok(); }}
Be careful with complex filter combinations - they can make debugging difficult.
Consider breaking down very complex logic into multiple simpler handlers.