Framework handler и transport APIs требуют Telegram bot services.
Правильный order:
builder.Services.AddTelegramBot(options => options.Token = token);
builder.Services.AddTelegramHandlersFromAssembly(typeof(Program).Assembly);
builder.Services.AddLongPolling();AddTelegramHandlersFromAssembly(...) требует IWF.TeleFlow.Generators.
Исправление:
<PackageReference Include="IWF.TeleFlow.Generators" Version="..." PrivateAssets="all" />Потом пересобери application.
Если generated registration не нужен, используй:
builder.Services.AddTelegramHandler<StartHandler>();Или зарегистрируй module явно:
builder.Services.AddTelegramModule<AdminHandlers>();Не переходи на deprecated reflection assembly registration как способ починить missing generated metadata.
State и filter attributes ограничивают handler, но сами не route-ят updates.
Неправильно:
[State("registration:name")]
[HasText]
public Task Name(MessageContext ctx, CancellationToken ct)
{
return Task.CompletedTask;
}Правильно:
[Message]
[State("registration:name")]
[HasText]
public Task Name(MessageContext ctx, CancellationToken ct)
{
return Task.CompletedTask;
}Используй [Message], [Command], [Callback], [ChatMemberUpdated] или другой явный route attribute перед state и filter constraints.
TeleFlow валидирует параметры handler methods до нормальной обработки updates. Если handler просит сервис, этот сервис должен быть зарегистрирован в DI:
public sealed class TicketHandler
{
[CommandTemplate("ticket {id:long}")]
public Task Ticket(
MessageContext ctx,
ITicketRepository tickets,
CancellationToken ct)
{
// ...
}
}Зарегистрируй dependency до сборки приложения:
builder.Services.AddScoped<ITicketRepository, EfTicketRepository>();То же правило действует для Telegram error handlers и custom filters.
ITelegramCurrentUpdateAccessor scoped на один входящий Telegram update. Он работает внутри handlers, middleware и scoped services, до которых дошёл update pipeline.
Он не работает из application startup, background jobs, singleton services или кода, который выполняется до появления update.
Используй его из scoped services:
public sealed class UserService(ITelegramCurrentUpdateAccessor current)
{
public long RequireUserId()
{
return current.User?.Id
?? throw new InvalidOperationException("Для этой операции нужен Telegram user.");
}
}Не внедряй его в singleton services.
Да. TeleFlow не важно, откуда пришёл token. Прочитай его через обычную .NET configuration и явно передай resolved value:
builder.Services.AddTelegramBot(options =>
{
options.Token = configuration["Telegram:BotToken"]
?? throw new InvalidOperationException("Telegram:BotToken is not configured.");
});Смотри Конфигурация и секреты.
Проверь:
- update type: message, callback, chat member;
- command prefix;
- text exact match vs contains;
- state requirement;
- class-level filters;
- custom filter return value;
- allowed updates for long polling.
Зарегистрируй state storage:
builder.Services.AddMemoryStateStorage();Для custom storage убедись, что IStateStore и state middleware registered.
Wizard back требует state history storage. AddMemoryStateStorage() его регистрирует. Custom storage должен предоставить IStateHistoryStore.
Telegram callback data ограничен 64 UTF-8 bytes. Используй compact payloads:
[CallbackData("t")]
public sealed record TicketAction(long Id, string A);Не клади large JSON payloads в callback data.
Если в логах есть Telegram callback data failed to deserialize, callback
совпал с typed [Callback<TPayload>] route по compact prefix и количеству
fields, но payload не удалось декодировать. Частые причины:
- пользователь нажал старую inline-кнопку после изменения callback payload type;
- numeric, boolean или enum field содержит invalid value;
- другой компонент бота сгенерировал callback data с тем же prefix, но другим field format.
TeleFlow считает такой typed route не сматченным, поэтому raw callback fallback может ответить пользователю. Проектируй callback payloads так, чтобы они переживали версии: используй короткие стабильные prefixes, передавай IDs вместо больших объектов и заводи новый prefix, когда deployed callback shape меняется несовместимо.
Проверь SecretToken configuration и Telegram webhook settings. Incoming request должен использовать expected secret token.
Telegram может вернуть pending updates после downtime. Current public API не документирует drop-pending-updates option. Deployment и startup behavior нужно проектировать с учётом pending updates.