Модель приложения¶
TeleFlow applications используют ту же форму, что и обычные .NET services:
- создать application builder;
- зарегистрировать services;
- зарегистрировать Telegram framework services;
- зарегистрировать handlers;
- зарегистрировать один update source;
- собрать и запустить приложение.
var builder = TeleFlowApplication.CreateBuilder(args);
builder.Services.AddTelegramBot(options => options.Token = token);
builder.Services.AddMemoryStateStorage();
builder.Services.AddTelegramHandlersFromAssembly(typeof(Program).Assembly);
builder.Services.AddLongPolling();
await using var app = builder.Build();
await app.RunAsync();
Если приложение уже использует Microsoft.Extensions.Hosting, подключай optional hosting adapter вместо ручного Build() у TeleFlowApplication:
using Microsoft.Extensions.Hosting;
using TeleFlow.Framework.Hosting;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddTelegramBot(options => options.Token = token);
builder.Services.AddMemoryStateStorage();
builder.Services.AddTelegramHandlersFromAssembly(typeof(Program).Assembly);
builder.Services.AddLongPolling();
builder.Services.AddTeleFlowHostedService();
await builder.Build().RunAsync();
Hosted service использует service provider от host-а. Он не создаёт второй DI container и не владеет provider disposal. Не используй hosted service для ASP.NET Core webhook apps: webhook processing управляется endpoint routing.
Основные понятия¶
Update source¶
Update source производит updates. Framework long polling и framework webhooks являются update sources. В running application должен быть один IUpdateSource.
Update processor¶
Update processor создаёт UpdateContext, запускает middleware и передаёт update в dispatcher.
Middleware¶
Middleware оборачивает выполнение update. Built-in middleware отвечает за logging, exception handling, state и rate limiting там, где они зарегистрированы.
Dispatcher¶
Dispatcher выбирает и вызывает подходящий handler. Telegram-specific dispatching находится вне TeleFlow.Framework.Core.
Handler¶
Handler - обычный class с method, который TeleFlow может вызвать. Routing metadata задаётся атрибутами.
Application lifecycle¶
TeleFlow lifecycle tasks выполняются вокруг update source:
- startup tasks запускаются в порядке регистрации;
- update source стартует и обрабатывает updates;
- shutdown tasks запускаются в обратном порядке регистрации после остановки update source.
Используй lifecycle tasks для startup/shutdown работы, которая принадлежит процессу бота:
builder.Services.AddTeleFlowStartupTask<ConfigureBotCommands>();
builder.Services.AddTeleFlowShutdownTask<FlushMetrics>();
public sealed class ConfigureBotCommands(ITelegramClient bot) : ITeleFlowStartupTask
{
public async ValueTask ExecuteAsync(CancellationToken ct = default)
{
await bot.SetMyCommandsAsync(
commands:
[
BotCommands.Create("start", "Start"),
BotCommands.Ephemeral("help", "Показать личную справку")
],
cancellationToken: ct);
}
}
Lifecycle tasks не являются Telegram handlers. Они не получают MessageContext, CallbackQueryContext или fake updates. TeleFlow создаёт их через dependency injection в отдельном lifecycle scope, поэтому scoped application services можно использовать безопасно.
BotCommands явно задаёт смысл команды. Create(...) создаёт обычную команду, а Ephemeral(...) выставляет Telegram-флаг is_ephemeral: в группе или супергруппе команда и её ответ видны только вызвавшему пользователю. Этот helper не ищет handlers и не публикует команды автоматически. Telegram по-прежнему принимает для меню только имена команд по правилам Bot API, поэтому используй строчное английское имя вроде help, а локальные алиасы добавляй отдельно.
Если startup task падает, update processing не стартует. Если update source падает уже после успешного startup, shutdown tasks всё равно выполняются, а исходная ошибка пробрасывается наружу. Если shutdown тоже падает, TeleFlow сообщает обе ошибки.
Не используй lifecycle tasks для long-running background jobs. Для отдельной фоновой работы используй обычные .NET primitives: IHostedService или BackgroundService.
Telegram contexts¶
Telegram handlers получают context objects, в которых есть текущий update, Telegram client, state и небольшие action helpers.
Общие свойства из TelegramUpdateContext:
| Property | Что означает |
|---|---|
Bot |
Low-level ITelegramClient. Используй его для полного доступа к Bot API. |
Update |
Raw Telegram Update. |
State |
Facade текущего state. |
Wizard |
Wizard navigation поверх state history. |
Chat |
Helper для typing, upload actions и похожих indicators. |
CancellationToken |
Framework cancellation token текущего update. |
Services |
Service provider для advanced scenarios. В обычном handler code лучше DI parameters или constructor injection. |
Message handlers используют MessageContext:
[Command("whoami")]
public Task WhoAmI(MessageContext ctx, CancellationToken ct)
{
var id = ctx.Sender?.Id;
var name = ctx.User?.FullName ?? "unknown";
return ctx.Message.AnswerAsync($"User: {name}, id: {id}", ct);
}
ctx.Message содержит message actions: AnswerAsync, ReplyAsync, AnswerPhotoAsync, ReplyDocumentAsync, SendEphemeralAsync, DeleteAsync. Эти helpers нацелены на current chat. Используй ctx.Bot.*Async, когда target chat или method surface должны быть явными.
Callback handlers используют CallbackQueryContext:
[Callback]
public async Task Handle(CallbackQueryContext ctx, CancellationToken ct)
{
await ctx.Callback.AnswerAsync(ct);
await ctx.Callback.EditTextAsync("Done.", ct);
}
Chat member handlers используют ChatMemberUpdatedContext:
[ChatMemberUpdated]
public Task Audit(ChatMemberUpdatedContext ctx, IAuditLog audit, CancellationToken ct)
{
return audit.RecordAsync(ctx.TelegramChat.Id, ctx.Member.Id, ct);
}
ctx.Chat.ActionAsync(...) сразу отправляет chat action и поддерживает его, пока не будет disposed возвращённый lease:
await using var typing = await ctx.Chat.ActionAsync(ChatAction.Typing, ct);
await reportService.BuildAsync(ct);
await ctx.Message.AnswerAsync("Report is ready.", ct);
Почему TeleFlow.Framework.Core transport-agnostic¶
TeleFlow.Framework.Core владеет application, middleware, update processing, state contracts и replacement points. Он не знает про Telegram message fields, callbacks, Bot API methods или Telegram update types.
Telegram behavior живёт в Telegram-пакетах:
TeleFlow.Telegram.ClientTeleFlow.FrameworkTeleFlow.Framework.LongPollingTeleFlow.Framework.Webhooks- raw transport packages
Так dependency direction остаётся чистым, а framework проще тестировать.
Startup failure - это намеренно¶
TeleFlow предпочитает ранние configuration errors вместо best-effort ambiguity. Примеры:
AddTelegramBot(...)должен быть вызван до framework handlers и transports.AddLongPolling(...)иAddWebhook(...)не должны одновременно владетьIUpdateSource.AddTelegramHandlersFromAssembly(...)требует generated metadata.- Options валидируются во время регистрации.
Это намеренное поведение. Бот должен падать на startup, если configuration wrong, а не после первого production update.
Минимальное direct client app¶
Если handlers не нужны, используй client package напрямую:
using Microsoft.Extensions.DependencyInjection;
using TeleFlow.Telegram;
var services = new ServiceCollection();
services.AddTelegramClient(options =>
{
options.Token = token;
});
using var provider = services.BuildServiceProvider();
var bot = provider.GetRequiredService<ITelegramClient>();
var me = await bot.GetMeAsync();
Console.WriteLine(me.Username);
Минимальное framework app¶
Framework нужен, когда нужны routing, filters, callbacks, state и transports:
builder.Services.AddTelegramBot(options => options.Token = token);
builder.Services.AddTelegramHandlersFromAssembly(typeof(Program).Assembly);
builder.Services.AddLongPolling();
Замена core policies¶
TeleFlow exposes replacement APIs для реальных extension points:
services.AddUpdateSource<MyUpdateSource>();
services.AddUpdateDispatcher<MyDispatcher>();
services.AddCallbackDataSerializer<MySerializer>();
services.AddStateStore<MyStateStore>();
services.AddStateDataStore<MyStateDataStore>();
services.AddStateHistoryStore<MyHistoryStore>();
services.AddStateKeyFactory<MyStateKeyFactory>();
services.AddTeleFlowStartupTask<MyStartupTask>();
services.AddTeleFlowShutdownTask<MyShutdownTask>();
Это advanced APIs. Большинству приложений лучше начать с framework transports и memory storage, а потом заменить только то, что стало инфраструктурным требованием.