MinimalTelegramBot.StateMachine.Abstractions
0.0.11
See the version list below for details.
dotnet add package MinimalTelegramBot.StateMachine.Abstractions --version 0.0.11
NuGet\Install-Package MinimalTelegramBot.StateMachine.Abstractions -Version 0.0.11
<PackageReference Include="MinimalTelegramBot.StateMachine.Abstractions" Version="0.0.11" />
paket add MinimalTelegramBot.StateMachine.Abstractions --version 0.0.11
#r "nuget: MinimalTelegramBot.StateMachine.Abstractions, 0.0.11"
// Install MinimalTelegramBot.StateMachine.Abstractions as a Cake Addin #addin nuget:?package=MinimalTelegramBot.StateMachine.Abstractions&version=0.0.11 // Install MinimalTelegramBot.StateMachine.Abstractions as a Cake Tool #tool nuget:?package=MinimalTelegramBot.StateMachine.Abstractions&version=0.0.11
Welcome to the Minimal Telegram Bot project
Minimal Telegram Bot is a modern .NET framework for building Telegram Bots using simple and concise syntax inspired by ASP.NET Core Minimal APIs.
Intentions
The development of a Minimal Telegram Bot project was started as an attempt to solve the problem with the lack of a single convenient solution for Telegram bot development on the .NET platform.
A great community-approved Telegram Bot API wrapper already exists in .NET. However, creating bots for more complex cases using only a bare-bones wrapper soon becomes cumbersome and unsupportable. Existing solutions that solve such a problem were made very focused on the specific author's problem and not fit well to wider scope of demands, and some of the solutions are abandoned as of today.
With some experience in development and other languages, I developed a proof of concept where writing bots was made way easier, hiding unnecessary boilerplate details. The developer and consumer of this project now only need to focus on their tasks, write the code that is needed here and now to solve the business tasks and not worry about the rest.
Considerations
Detailed documentation is still in progress with framework's public APIs so some changes are possible in the future. The project roadmap includes considerations for changing the policy of support and updates as well as the communication practices with the audience if it gains enough audience.
At the moment, this framework already has enough features and customization mechanisms to use in real projects. Future plans are to create more public API methods for user convenience, tailor the API and provide full documentation.
Features
- Support for the latest Telegram Bot API version, receiving fast updates thanks to Telegram.Bot, the most popular .NET Client for Telegram Bot API
Framework features
- Fully parallel Telegram updates handling
- Pipeline (middleware) building just like in ASP.NET Core
- Powerful and customizable updates handling and filtering similar to ASP.NET Core Minimal APIs
- Integration of dependency injection, configuration and logging from ASP.NET Core
Extensions
- Support for the Finite State Machine concept for Telegram bots using StateMachine extension (WIP)
- Built-in bot localization features using Localization extension (WIP)
Getting updates from Telegram
- Support getting updates via both webhook and polling
- Provides direct responses to webhook requests
Getting started
Prerequisites
This project is using .NET 8 for now, so be sure to install the appropriate version of .NET, and that's all you need to start developing.
New project
Start by creating an "Empty" ASP.NET Core application using the command line:
dotnet new web -n MyBot -f net8.0
Or create a new ASP.NET Core web application in your IDE, and choose "Empty" for the project template.
Installation
Install the library using NuGet package manager in your IDE:
dotnet add package MinimalTelegramBot
In addition, you can add some extension packages that provide Localization and State Machine features:
dotnet add package MinimalTelegramBot.Localization
dotnet add package MinimalTelegramBot.StateMachine
Usage
Basic setup
In your Program.cs
you can use following basic setup:
using MinimalTelegramBot.Builder;
using MinimalTelegramBot.Handling;
var builder = BotApplication.CreateBuilder(args);
var bot = builder.Build();
bot.HandleCommand("/start", () => "Hello, World!");
bot.Run();
In the code above we are creating BotApplication
using builder just like in web applications. When the bot
instance are set up and ready for handling configuration, we call HandleCommand()
with specified /start
command and return Hello, World!
message as a result.
By default, polling method for getting updates from Telegram is used because it's faster to start development with polling method and polling requires less effort to configure. Bot token is specified in configuration with "BotToken"
key. For local development you can set your bot token using dotnet user-secrets tool:
dotnet user-secrets init
dotnet user-secrets set "BotToken" "your bot token"
In other environments you can use .env
files or just set bot token in appsettings.json
:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"BotToken": "your bot token"
}
Ensure that your bot token is not included in version control to prevent unauthorized access to your bot.
If you have any trouble with telegram bot token or @BotFather, read the official tutorial.
When all configuration is complete, just run program with dotnet run
or via IDE's interface and test your bot.
Advanced handling examples
Localizer usage
Localization is essential when creating bots for users across multiple regions. Here, the localizer service allows you to retrieve messages dynamically based on the user's locale. How to add localizer in bot app with single locale before building the bot app:
builder.Services.AddSingleLocale(
new Locale("en"),
locale => locale.EnrichFromFile("Localization/en.yaml"));
How to use localizer services after building bot app:
bot.UseLocalization();
To use different languages, you need to implement IUserLocaleProvider
interface, in that way you provide the context for resolving user's locale. You can find more details about adding localization and different languages in the code samples.
The command below uses localizer to respond to the /start
command with a "HelloText"
message retrieved and a dynamically generated keyboard based on the user's locale from method MenuKeyboard()
. See more on keyboards.
bot.HandleCommand("/start", (ILocalizer localizer) =>
{
var helloText = localizer["HelloText"];
var keyboard = MenuKeyboard(localizer);
return Results.Message(helloText, keyboard);
});
Callback data handling
This handler handles callback data "Photo"
and responses with photo and description.
Here, general Handle()
method is used with FilterCallbackData()
filter.
Note, wwwroot
folder comes from ASP.NET Core static file serving.
bot.Handle(() =>
Results.Photo("wwwroot/cat.jpeg", "Little cat"))
.FilterCallbackData(x => x == "Photo");
Parameter parsing
This example handles the /add
command by parsing user input into AddCommandModel
and responding with a sum of two parsed numbers or error message, depending on the input's validity. Example: /add 1.3 5.7
outputs 7
. Attribute [UseFormatProvider]
allows culture-specific number parsing like comma- or point-based decimal separator.
bot.HandleCommand("/add", (
[UseFormatProvider] AddCommandModel model,
ILocalizer localizer) =>
{
return model.IsError
? localizer["ParsingError"]
: localizer["AddCommandTemplate", model.Result];
});
Here example of AddCommandModel
class, note that implementing an interface ICommandParser
. This interface is essential for ensuring that command will be parsed.
public class AddCommandModel : ICommandParser<AddCommandModel>
{
public double A { get; set; }
public double B { get; set; }
public bool IsError { get; set; }
public double Result => A + B;
public static AddCommandModel Parse(
string command,
IFormatProvider? formatProvider = null)
{
var parts = command.Split(' ');
if (parts.Length < 3 ||
!double.TryParse(parts[1], formatProvider, out var a) ||
!double.TryParse(parts[2], formatProvider, out var b))
{
return new AddCommandModel { IsError = true, };
}
return new AddCommandModel { A = a, B = b, };
}
}
Callback data parsing is also supported using a similar API.
Dependency injection and keyed services
In this example, we handle commands that retrieve data from a specific service registered in DI container with a key. The NameService
is used here to provide different names depending on the command. By using the FromKeyedServices
attribute, we dynamically inject the appropriate service into the handler based on the command.
FromKeyedServices
attribute allows you to dynamically inject services registered with specific keys, such as FirstName
, or LastName
in this example.
Standard dependency injection techniques are also supported, handling context is a scope.
bot.HandleCommand("/firstname",
([FromKeyedServices("FirstName")] NameService nameService) =>
nameService.Name);
bot.HandleCommand("/lastname",
([FromKeyedServices("LastName")] NameService nameService) =>
nameService.Name);
Async weather service example
This example demonstrates how to handle complex interactions asynchronously, using a weather service to fetch real-time data.
Here, general Handle()
method is used with FilterCallbackData()
filter.
Note, here string messageText
directly injected from incoming message, and handler catches all messages by using FilterUpdateType(UpdateType.Message)
filter.
bot.Handle(async (string messageText, WeatherService weatherService) =>
{
var weather = await weatherService.GetWeather();
var keyboard = new InlineKeyboardMarkup(InlineKeyboardButton.WithCallbackData("Hello", "Hello"));
return ($"Hello, {messageText}, weather is {weather}", keyboard);
}).FilterUpdateType(UpdateType.Message);
Error handling
This example shows default error handling. Command /throw
randomly decides to throw an exception and default error handling mechanism gracefully caches an exception and logs it preventing bot app from unexpected shutdown. If no error occurs, the bot responds with message 'Ok'.
bot.HandleCommand("/throw", () =>
{
if (Random.Shared.Next(0, 2) == 0)
{
throw new Exception("Error");
}
return Results.Message("Ok");
});
If you need custom error handling, you can wrap bot app execution pipeline (middleware) in your own middleware like this:
bot.Use(async (context, next) =>
{
try
{
await next(context);
}
catch (Exception ex)
{
// Custom exception handling.
}
});
Ensure that this middleware is placed before other handlers in the pipeline.
More advanced use-cases
If you need examples of more complex use-cases and features, you can check code example here or ask any question in Telegram group.
Additional resources
Check out some resources that can help you develop good bots:
- Code samples
- Localization extension NuGet package
- StateMachine extension NuGet package
- Telegram.Bot API wrapper GitHub
- Telegram.Bot API wrapper documentation
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. 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. |
-
net8.0
- No dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on MinimalTelegramBot.StateMachine.Abstractions:
Package | Downloads |
---|---|
MinimalTelegramBot
Minimal Telegram Bot is a modern .NET framework for building Telegram Bots using simple and concise syntax inspired by ASP.NET Core Minimal APIs. |
|
MinimalTelegramBot.StateMachine
Provides state machine functionality for the Minimal Telegram Bot Framework. |
GitHub repositories
This package is not used by any popular GitHub repositories.