BotFramework.NET
2.1.2
See the version list below for details.
dotnet add package BotFramework.NET --version 2.1.2
NuGet\Install-Package BotFramework.NET -Version 2.1.2
<PackageReference Include="BotFramework.NET" Version="2.1.2" />
paket add BotFramework.NET --version 2.1.2
#r "nuget: BotFramework.NET, 2.1.2"
// Install BotFramework.NET as a Cake Addin
#addin nuget:?package=BotFramework.NET&version=2.1.2
// Install BotFramework.NET as a Cake Tool
#tool nuget:?package=BotFramework.NET&version=2.1.2
BotFramework
Фреймворк для создания ботов под любую платформу на основе обработки запросов с помощью цепочки обязанностей
Использование
Все примеры ниже оформлены с использованием Telegram.Bot
Регистрация зависимостей
Перед началом работы зарегистрируйте зависимости и создайте ServiceProvider:
var services = new ServiceCollection();
/* Здесь Вы можете внедрить свои зависимости */
services.AddBotFramework()
.AddHandler<ExceptionHandler>()
.AddHandler<HelpCommand>()
.AddHandler<SendCommand>()
.AddHandler<MissingRequestHandler>();
var serviceProvider = services.BuildServiceProvider();
Метод AddBotFramework() добавляет основные классы фреймворка в контейнер зависимостей. AddHandler() регистрирует обработчик запроса указанного типа.
Конфигурация цепочки обработчиков
Как только все зависимости будут зарегистрированы, используйте BranchBuilder, чтобы сконфигурировать цепочку обработчиков:
var branchBuilder = new BranchBuilder(serviceProvider); // или var branchBuilder = serviceProvider.GetRequiredService<IBranchBuilder>();
branchBuilder.UseHandler<ExceptionHandler>()
.UseCommand<HelpCommand>()
.UseCommand<SendCommand>()
.UseHandler<MissingRequestHandler>();
Метод UseHandler() добавляет обработчик в цепочку. UseCommand() добавляет команду в обработчик. По сути, команда и есть обработчик, а их отличие в том, что команда вызывается только при соблюдении определенных условий, описанных в реализации этой команды (например, запрос содержит текстовую команду). Также существует метод UseAnotherBranch(), которая конфигурирует вложенную цепочку обработчиков. Пример ниже конфигурирует цепочку обработчиков таким образом, чтобы при получении сообщения с текстовой командой и видео, запускался механизм проверки формата ролика в CheckVideoFormatHandler, а затем выполнений действий по обработке в ProcessVideoHandler:
branchBuilder.UseHandler<ExceptionHandler>()
.UseAnotherBranch
(
request => update.IsVideo() && update.IsCommand(), // Пользовательские методы
anotherBranchBuilder =>
{
anotherBranchBuilder.UseHandler<CheckVideoFormatHandler>()
.UseHandler<ProcessVideoHandler>();
}
)
.UseCommand<HelpCommand>();
Метод Build() построит готовую цепочку в виде RequestDelegate. Достаточно вызывать этот делегат каждый раз, когда запрос для обработки будет готов будет готов. Например, получение обновления от Telegram:
var branch = branchBuilder.Build();
var request = GetLastUpdate(); // Пользовательский метод
await branch(request);
Создание обработчиков
Чтобы создать новый обработчик, реализуйте интерфейс IRequestHandler. Пример ниже уведомляет пользователя о том, что бот не может обработать запрос:
public class MissingUpdateHandler : IRequestHandler
{
private readonly ILogger<MissingUpdateHandler> _logger;
private readonly ITelegramBotClient _client;
public MissingUpdateHandler(ILogger<MissingUpdateHandler> logger, ITelegramBotClient client)
{
_logger = logger;
_client = client;
}
public async Task HandleAsync(object request, RequestDelegate nextHandler)
{
var update = request as Update;
if (update is not null)
{
_logger.LogWarning($"No handler for request with type: {update.Type}");
if (update.CallbackQuery is CallbackQuery callbackQuery)
{
await _client.AnswerCallbackQueryAsync
(
callbackQuery.Id,
text: "Невозможно обработать Ваш запрос"
);
}
else if (update.GetChatId() is long chatId && update.GetChatType() is not ChatType.Group) // Пользовательские методы
{
await _client.SendTextMessageAsync
(
chatId,
text: "Некорректный запрос. Используйте /help для получения списка доступных команд"
);
}
}
}
}
Обратите внимание, что все обработчики поддерживают инъекцию зависимостей.
Создание команд
Чтобы создать новую команду, используйте интерфейс ICommandHandler. Пример ниже по команде "/help" или "/start" выводит пользователю подсказку по работе с ботом:
[CommandText("/help, /start")]
public class StartCommand : ICommandHandler
{
private readonly ILogger<StartCommand> _logger;
private readonly ITelegramBotClient _client;
public StartCommand(ILogger<StartCommand> logger, ITelegramBotClient client)
{
_logger = logger;
_client = client;
}
public async Task HandleAsync(object request, RequestDelegate nextHandler)
{
var stringBuilder = new StringBuilder();
stringBuilder.AppendLine("<b>С помощью данного бота Вы можете: ...</b>");
var update = request as Update;
if (update is not null)
{
var message = update.Message;
var chatId = message.Chat.Id;
await _client.SendChatActionAsync
(
chatId,
chatAction: ChatAction.Typing
);
await _client.SendTextMessageAsync
(
chatId,
text: stringBuilder.ToString(),
parseMode: ParseMode.Html,
disableWebPagePreview: true
);
_logger?.LogInformation("Help/Start command processed");
}
}
public bool CanHandle(IServiceProvider serviceProvider, object request)
{
var botInfo = _client.GetMeAsync()
.GetAwaiter()
.GetResult();
return request is Update update &&
update.IsCommand() &&
update.Message is Message message &&
message.IsContainsBotMention(botInfo) &&
this.TextIsCommandAlias(message.Text);
}
}
Атрибут CommandText позволяет через запятую определить на какие текстовые команды будет реагировать данный обработчик. Метод CanHandle() определяет при каких условиях команда может быть выполнена. В примере выше, условие выполнится, если сообщение включает в себя упоминание бота и является текстовой командой, указанной в атрибуте CommandText. Команды также, как и обычные обработчики, поддерживают инъекцию зависимостей. В дополнение к классическому DI, CanHandle() содержит в качестве параметра IServiceProvider.
Создание пошаговых обработчиков
Начиная с v2.1.1 Вы можете конфигурировать пошаговые обработчики, используя метод UseStepsFor() из интерфейса IBranchBuilder:
var branchBuilder = new BranchBuilder(serviceProvider); // или var branchBuilder = serviceProvider.GetRequiredService<IBranchBuilder>();
branchBuilder.UseHandler<ExceptionHandler>()
.UseStepsFor<Command>(stepsBuilder =>
{
stepsBuilder.UseStepHandler<AskFirstnameHandler>()
.UseStepHandler<AskLastnameHandler>();
});
Пошаговые обработчики можно определить только для команд. Сами по себе пошаговые обработчики являются командами, но без ссылки на следующий обработчик в цепочке. Каждый пошаговый обработчик позволяет получить запрос из предыдущего шага и ответ на него из текущего шага. Определить пошаговый обработчик можно используя абстрактный класс StepHandlerBase<TPreviousRequest, TCurrentRequest>:
internal class AskLastnameHandler : StepHandlerBase<string, string>
{
public override Task HandleAsync(string previousRequest, string currentRequest)
{
Console.WriteLine($"Имя: {previousRequest}");
Console.WriteLine($"Фамилия: {currentRequest}");
return Task.CompletedTask;
}
}
Создание бота
<details> <summary>До v1.0.2</summary>
BotFramework имеет абстракцию BotBase для того, чтобы изолировать вызовы RequestDelegate в одном месте. Это вовсе необязательно и вы вольны реализовывать вызовы Вашей цепочки так, как Вам хочется. Пример ниже показывает, как LongPolling-сервис вызывает RequestDelegate с именем rootHandler при получении новых обновлений от Telegram:
public class TelegramBot : BotBase
{
private readonly ILogger _logger;
private readonly ILongPollingService _longPollingService;
private readonly CancellationTokenSource _cancellationTokenSource;
public TelegramBot(RequestDelegate rootHandler, ILogger<TelegramBot> logger,
ILongPollingService longPollingService) : base(rootHandler)
{
_logger = logger;
_longPollingService = longPollingService;
_cancellationTokenSource = new CancellationTokenSource();
}
public override void Run()
{
_longPollingService.Receive
(
_rootHandler,
_cancellationTokenSource.Token
);
_logger?.LogInformation("Bot is running...");
}
public override void Stop()
{
_cancellationTokenSource.Cancel();
_logger?.LogInformation("Bot stopped");
}
}
</details>
<details> <summary> Начиная с v2.1.1</summary>
Абстракция BotBase вырезана и больше не используется
</details>
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 is compatible. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Extensions.DependencyInjection (>= 5.0.2)
- Microsoft.Extensions.Logging (>= 5.0.0)
-
net5.0
- Microsoft.Extensions.DependencyInjection (>= 5.0.2)
- Microsoft.Extensions.Logging (>= 5.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
5.1.0 | 354 | 11/9/2022 |
5.0.0 | 336 | 11/4/2022 |
4.0.0 | 440 | 7/12/2022 |
3.1.0 | 437 | 7/11/2022 |
3.0.0 | 441 | 7/2/2022 |
2.1.8 | 422 | 4/24/2022 |
2.1.7 | 296 | 11/22/2021 |
2.1.6 | 364 | 11/22/2021 |
2.1.5 | 575 | 11/21/2021 |
2.1.4 | 1,175 | 11/20/2021 |
2.1.3 | 360 | 11/19/2021 |
2.1.2 | 312 | 11/18/2021 |
2.1.1 | 445 | 11/17/2021 |
1.0.2 | 353 | 10/24/2021 |
1.0.1 | 405 | 10/24/2021 |