Middleware
Введение
Pipeline TeleFlow реализован как цепочка IHandler<T>.
Каждое звено этой цепочки является middleware.
Middleware получает объект контекста, выполняет обработку и передаёт управление следующему звену.
Примечание
Большинство пользовательских расширений Pipeline реализуются именно через добавление собственных middleware.
—
Типы middleware
В Pipeline можно выделить два типа middleware.
Контекстные middleware
Работают с уже существующим типом контекста и не изменяют его тип.
Например:
IHandlerMiddleware<UpdateContext>IHandlerMiddleware<SessionContext>IHandlerMiddleware<CommandResultContext>
Это естественная точка расширения Pipeline. Именно здесь обычно добавляется пользовательская логика.
—
Переходные middleware
Преобразуют один тип контекста в другой.
Например:
Update → UpdateContextUpdateContext → SessionContextSessionContext → CommandResultContext
Эти middleware формируют структуру Pipeline.
Примечание
В большинстве случаев переходные middleware не изменяются. При необходимости их можно переопределить и встроить в собственную конфигурацию Pipeline.
—
Интерпретаторы
Middleware, работающие с CommandResultContext,
образуют цепочку интерпретаторов.
Именно они определяют, как обрабатывается результат выполнения команды.
В конце цепочки интерпретаторов всегда находится
DefaultCommandInterpreter:
public class DefaultCommandInterpreter : IHandler<CommandResultContext>
{
private readonly IChatSessionStore _sessionStore;
public async Task Handle(CommandResultContext args)
{
var chatId = args.GetService<IChatIdProvider>().GetChatId();
await _sessionStore.RemoveAsync(chatId);
throw new Exception(
"No command interpreter matched the command result of type "
+ args.CommandResult.GetType().FullName);
}
public DefaultCommandInterpreter(IChatSessionStore sessionStore)
{
_sessionStore = sessionStore;
}
}
Этот обработчик выполняется,
если ни один интерпретатор не обработал CommandResult.
—
Порядок выполнения
Middleware выполняются строго в порядке их регистрации.
Каждый middleware:
Получает контекст.
Выполняет свою логику.
Передаёт управление через
Next.Handle(...).
Если управление не передаётся дальше, цепочка на текущем этапе завершается.
—
Когда писать собственный middleware
Собственный middleware имеет смысл добавлять, если требуется:
глобальное логирование;
централизованная обработка ошибок;
изменение инфраструктурного поведения;
дополнительная обработка контекста до или после команды.
Если логика относится к конкретной команде, следует использовать Interceptor.