Skip to content

Latest commit

 

History

History
1204 lines (867 loc) · 37.6 KB

README.md

File metadata and controls

1204 lines (867 loc) · 37.6 KB

.NET Telegram Bot Framework - Context based addon

NuGet version (TelegramBotBase) Telegram chat

License Package Downloads

Showcase: @TGBaseBot

Support group: @tgbotbase

Discord Server: https://discord.gg/V3PxreDYfE

Releases: GitHub

Need your own bot? Get in touch https://t.me/botbasebuilder

on X: @florian_zevedei

Donate

Paypal: https://paypal.me/majmccloud

Bitcoin: 1GoUJYMwAvBipQTfw2FKydAz12J8RDyeJs / bc1qqwlp0p5ley29lsu6jhe0qv7s7963kfc7d0m53d

Etherium: 0xAf3835104c2C3E5b3e721FA2c7365955e87DB931

Litecoin: LRhF1eB7kneFontcDRDU8YjJhEm2GoYHch

Dashcoin: XudiUwWtSmAJj1QDdVW7jocQumJFLsyoGZ

Tron: TYVZSykaVT1nKZnz9hjDgBRNB9VavU1bpW

BitTorrent: TYVZSykaVT1nKZnz9hjDgBRNB9VavU1bpW


Index


Quick start

First of all, create a new empty dotnet console project and paste some code:

// public async Task Main(string[] args)

var bot = BotBaseBuilder
    .Create()
    .WithAPIKey("{YOUR API KEY}") // do not store your API key as plain text in project sources
    .DefaultMessageLoop()
    .WithStartForm<StartForm>()
    .NoProxy()
    .CustomCommands(a =>
    {
        a.Start("Starts the bot");
    })
    .NoSerialization()
    .UseEnglish()
    .UseSingleThread()
    .Build();

// Upload bot commands to BotFather
await bot.UploadBotCommands();

// Start your Bot
await bot.Start();

The BotBase class will manage a lot of things for you, like bot commands, action events and so on. StartForm is your first form which every user will get internally redirected to, just like a start page. It needs to be a subclass of FormBase you will find in namespace TelegramBotBase.Base

Every Form has some events which will get raised at specific times. In every form, you are able to get notes about the Remote Device, like ChatId and other stuff your carrying. From there you build up your bots:

public class Start : FormBase
{
     
    public Start()
    {
        //Additional event handlers
        Init += Start_Init;
        Opened += Start_Opened;
        Closed += Start_Closed;
    }

    // Gets invoked on initialization, before navigation
    private async Task Start_Init(object sender, Args.InitEventArgs e)
    {
    }

    // Gets invoked after opened
    private async Task Start_Opened(object sender, EventArgs e)
    {
    }

    // Gets invoked after form has been closed
    private async Task Start_Closed(object sender, EventArgs e)
    {
    }

    // Gets invoked during Navigation to this form
    public override async Task PreLoad(MessageResult message)
    {
    }

    // Gets invoked on every Message/Action/Data in this context
    public override async Task Load(MessageResult message)
    {
        // `Device` is a wrapper for current chat - you can easily respond to the user
        await this.Device.Send("Hello world!");
    }

    // Gets invoked on edited messages
    public override async Task Edited(MessageResult message)
    {
    }

    // Gets invoked on Button clicks
    public override async Task Action(MessageResult message)
    {
    }

    // Gets invoked on Data uploades by the user (of type Photo, Audio, Video, Contact, Location, Document)
    public override async Task SentData(DataResult data)
    {
    }

    //Gets invoked on every Message/Action/Data to render Design or Response 
    public override async Task Render(MessageResult message)
    {
    }
}

Send a message after loading a specific form:

await this.Device.Send("Hello world!");

Want to go to a different form? Go ahead, create it, initialize it and navigate to it:

var form = new TestForm();
await this.NavigateTo(form);

Simplified builder

When migrating from a previous version or starting completely new, all these options can be a bit overwhelming. There's a function called QuickStart that simplifies building a bit.

var bot = BotBaseBuilder
    .Create()
    .QuickStart<StartForm>("{YOUR API KEY}")
    .Build();

await bot.Start();

Features

System calls & bot commands

Using BotFather you can add Commands to your bot. The user will see them as popups in a dialog. Before starting (and later, for sure), you could add them to your BotBase. If the message contains a command, a special event handler will get raised.

Below we have 4 commands.

/start - opens the start form

/form1 - navigates in this context to form1

/form2 - navigates in this context to form2

/params - demonstrates the use of parameters per command (i.e. /params 1 2 3 test ...)

var bot = BotBaseBuilder
    .Create()
    .WithAPIKey("{YOUR API KEY}")
    .DefaultMessageLoop()
    .WithStartForm<Start>()
    .NoProxy()
    .CustomCommands(a =>
    {
        a.Start("Starts the bot");
        a.Add("form1","Opens test form 1");
        a.Add("form2", "Opens test form 2");
        a.Add("params", "Returns all send parameters as a message.");
    })
    .NoSerialization()
    .UseEnglish()
    .UseSingleThread()
    .Build();

bot.BotCommand += async (s, en) =>
{
    switch (en.Command)
    {
        case "/form1":
            var form1 = new TestForm();
            await en.Device.ActiveForm.NavigateTo(form1);
            break;

        case "/form2":
            var form2 = new TestForm2();
            await en.Device.ActiveForm.NavigateTo(form2);
            break;

        case "/params":
            string m = en.Parameters.DefaultIfEmpty("").Aggregate((a, b) => a + " and " + b);
            await en.Device.Send("Your parameters are " + m, replyTo: en.Device.LastMessage);
            break;
    }
};

await bot.UploadBotCommands() 

await bot.Start();

On every input the user is sending back to the bot, the Action event gets raised. So here we could manage to send something back to him.

Text messages

public class SimpleForm : AutoCleanForm
{
    public SimpleForm()
    {
        DeleteSide = EDeleteSide.Both;
        DeleteMode = EDeleteMode.OnLeavingForm;

        Opened += SimpleForm_Opened;
    }

    private async Task SimpleForm_Opened(object sender, EventArgs e)
    {
        await Device.Send("Hello world! (send 'back' to get back to Start)\r\nOr\r\nhi, hello, maybe, bye and ciao");
    }

    public override async Task Load(MessageResult message)
    {
        // message.MessageText will work also, cause it is a string you could manage a lot different scenerios here
        var messageId = message.MessageId;

        switch (message.Command)
        {
            case "hello":
            case "hi":
                // Send a simple message
                await this.Device.Send("Hello you there !");
                break;
    
            case "maybe":
                // Send a simple message and reply to the one of himself
                await this.Device.Send("Maybe what?", replyTo: messageId);
                break;
    
            case "bye":
            case "ciao":
                // Send a simple message
                await this.Device.Send("Ok, take care !");
                break;
        }
    }
}

Buttons

public class ButtonTestForm : AutoCleanForm
{
    public ButtonTestForm()
    {
        this.DeleteMode = eDeleteMode.OnLeavingForm;
        Opened += ButtonTestForm_Opened;
    }

    private async Task ButtonTestForm_Opened(object sender, EventArgs e)
    {
        await this.Device.Send("Hello world! (Click 'back' to get back to Start)");
    }

    public override async Task Action(MessageResult message)
    {
        var call = message.GetData<CallbackData>();
        await message.ConfirmAction();

        if (call == null)
            return;

        message.Handled = true;

        switch (call.Value)
        {
            case "button1":
                await this.Device.Send("Button 1 pressed");
                break;

            case "button2":
                await this.Device.Send("Button 2 pressed");
                break;

            case "button3":
                await this.Device.Send("Button 3 pressed");
                break;

            case "button4":
                await this.Device.Send("Button 4 pressed");
                break;

            case "back":
                var st = new Start();
                await this.NavigateTo(st);
                break;

            default:
                message.Handled = false;
                break;
        }
    }

    public override async Task Render(MessageResult message)
    {
        ButtonForm btn = new ButtonForm();

        btn.AddButtonRow(new ButtonBase("Button 1", new CallbackData("a", "button1").Serialize()), new ButtonBase("Button 2", new CallbackData("a", "button2").Serialize()));
        btn.AddButtonRow(new ButtonBase("Button 3", new CallbackData("a", "button3").Serialize()), new ButtonBase("Button 4", new CallbackData("a", "button4").Serialize()));
        btn.AddButtonRow(new ButtonBase("Google.com", "google", "https://www.google.com"), new ButtonBase("Telegram", "telegram", "https://telegram.org/"));
        btn.AddButtonRow(new ButtonBase("Back", new CallbackData("a", "back").Serialize()));

        await this.Device.Send("Click a button", btn);
    }
}

Custom controls

There is a bunch of ready to use controls. For example, progress bar.

public class ProgressTest : AutoCleanForm
{
    public ProgressTest()
    {
        this.DeleteMode = eDeleteMode.OnLeavingForm;
        Opened += ProgressTest_Opened;
    }

    private async Task ProgressTest_Opened(object sender, EventArgs e)
    {
        await this.Device.Send("Welcome to ProgressTest");
    }

    public override async Task Action(MessageResult message)
    {
        var call = message.GetData<CallbackData>();
        await message.ConfirmAction();

        if (call == null) return;

        TelegramBotBase.Controls.ProgressBar Bar = null;

        switch (call.Value)
        {
            case "standard":
                Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.standard);
                Bar.Device = this.Device;
                break;

            case "squares":
                Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.squares);
                Bar.Device = this.Device;
                break;

            case "circles":
                Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.circles);
                Bar.Device = this.Device;
                break;

            case "lines":
                Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.lines);
                Bar.Device = this.Device;
                break;

            case "squaredlines":
                Bar = new TelegramBotBase.Controls.ProgressBar(0, 100, TelegramBotBase.Controls.ProgressBar.eProgressStyle.squaredLines);
                Bar.Device = this.Device;
                break;

            case "start":
                var sf = new Start();
                await sf.Init();
                await this.NavigateTo(sf);
                return;

            default:
                return;
        }

        // Render Progress bar and show some "example" progress
        await Bar.Render();

        this.Controls.Add(Bar);

        for (int i = 0; i <= 100; i++)
        {
            Bar.Value++;
            await Bar.Render();

            Thread.Sleep(250);
        }
    }

    public override async Task Render(MessageResult message)
    {
        ButtonForm btn = new ButtonForm();

        btn.AddButtonRow(new ButtonBase("Standard", new CallbackData("a", "standard").Serialize()), new ButtonBase("Squares", new CallbackData("a", "squares").Serialize()));
        btn.AddButtonRow(new ButtonBase("Circles", new CallbackData("a", "circles").Serialize()), new ButtonBase("Lines", new CallbackData("a", "lines").Serialize()));
        btn.AddButtonRow(new ButtonBase("Squared Line", new CallbackData("a", "squaredlines").Serialize()));
        btn.AddButtonRow(new ButtonBase("Back to start", new CallbackData("a", "start").Serialize()));

        await this.Device.Send("Choose your progress bar:", btn);
    }

    public override async Task Closed()
    {
        foreach (var b in this.Controls)
        {
            await b.Cleanup();
        }

        await this.Device.Send("Ciao from ProgressTest");
    }
}

Forms advanced

Registration forms have never been so easy.

public class PerForm : AutoCleanForm
{
    public string EMail { get; set; }

    public string Firstname { get; set; }

    public string Lastname { get; set; }

    public async override Task Load(MessageResult message)
    {
        if (string.IsNullOrWhiteSpace(message.MessageText)) return;

        if (this.Firstname == null)
        {
            this.Firstname = message.MessageText;
            return;
        }

        if (this.Lastname == null)
        {
            this.Lastname = message.MessageText;
            return;
        }

        if (this.EMail == null)
        {
            this.EMail = message.MessageText;
            return;
        }
    }

    public async override Task Action(MessageResult message)
    {
        var call = message.GetData<CallbackData>();
        await message.ConfirmAction();

        if (call == null) return;

        switch (call.Value)
        {
            case "back":
                var start = new Start();
                await this.NavigateTo(start);
                break;
        }
    }

    public async override Task Render(MessageResult message)
    {
        if (this.Firstname == null)
        {
            await this.Device.Send("Please sent your firstname:");
            return;
        }

        if (this.Lastname == null)
        {
            await this.Device.Send("Please sent your lastname:");
            return;
        }

        if (this.EMail == null)
        {
            await this.Device.Send("Please sent your email address:");
            return;
        }

        string s = "";

        s += "Firstname: " + this.Firstname + "\r\n";
        s += "Lastname: " + this.Lastname + "\r\n";
        s += "E-Mail: " + this.EMail + "\r\n";

        ButtonForm bf = new ButtonForm();
        bf.AddButtonRow(new ButtonBase("Back", new CallbackData("a", "back").Serialize()));

        await this.Device.Send("Your details:\r\n" + s, bf);
    }
}

Another case, where every of these 3 inputs gets requested by different forms. Just for imagination of the possibilities.

Forms

There are some default forms to make the interaction with users easier.

  • AlertDialog Just a simple dialog with one Button.

  • AutoCleanForm A form which needs to be derived from. It will be delete all in the context sent messages to the user after every new message or on leaving the form and navigates somewhere else. Makes sense to create a feeling of a clean environment for the user. For instance if you have a multilevel menu. This will remove the previously shown menu, and renders the new sub/top level.

  • PromptDialog A simple dialog which will show a message and then wait for a text input (response).

  • ConfirmDialog A simple dialog which is able to show multiple buttons and a text message. The user could select one option and will get redirected to a different form, depending on the click.

Alert Dialog

AlertDialog ad = new AlertDialog("This is a message", "Ok");

ad.ButtonClicked += async (s, en) =>
{
    var fto = new TestForm2();
    await this.NavigateTo(fto);
};

await this.NavigateTo(ad);

AutoCleanForm

Just try it by yourself.

Prompt Dialog

PromptDialog pd = new PromptDialog("Please tell me your name ?");

pd.Completed += async (s, en) =>
{
    await this.Device.Send("Hello " + pd.Value);
};

await this.OpenModal(pd);

Confirm Dialog

ConfirmDialog cd = new ConfirmDialog("Please confirm", new ButtonBase("Ok", "ok"), new ButtonBase("Cancel", "cancel"));

cd.ButtonClicked += async (s, en) =>
{
    var tf = new TestForm2();

    // Remember only to navigate from the current running form. (here it is the prompt dialog, cause we have left the above already)
    await cd.NavigateTo(tf);
};

await this.NavigateTo(cd);

Controls

Label

A minimal control which allows to manage a classic "text" message and update its later without having to keep track of the message id.

Check the example project TelegramBotBase.Test/Tests/Controls/LabelForm.cs

Progress Bar

Check the example project TelegramBotBase.Test/Tests/ProgressTest.cs

Calendar Picker

Check the example project TelegramBotBase.Test/Tests/Controls/CalendarPickerForm.cs

Month Picker

Check the example project TelegramBotBase.Test/Tests/Controls/MonthPickerForm.cs

Tree View

Check the example project TelegramBotBase.Test/Tests/Controls/TreeViewForms.cs

Toggle Button

Check the example project TelegramBotBase.Test/Tests/Controls/ToggleButtonForm.cs

Button Grid

Check the example project TelegramBotBase.Test/Tests/Controls/ButtonGridForm.cs

Paging & Searching

Check the example project TelegramBotBase.Test/Tests/Controls/ButtonGridPadingForm.cs

Tagged Button Grid

Check the example project TelegramBotBase.Test/Tests/Controls/ButtonGridTagForm.cs

Checked Button List

Check the example project TelegramBotBase.Test/Tests/Controls/CheckedButtonListForm.cs

Multi Toggle Button

Check the example project TelegramBotBase.Test/Tests/Controls/MultiToggleButtonForm.cs

Localizations

The current available languages for controls are:

  • English
  • German
  • Persian
  • Russian

You can add other languages easily by creating a subclass of the TelegramBotBase/Localizations/Localization.cs class.

To set the default language set the Language property on the static TelegramBotBase/Localizations/Default.cs instance.

Groups

For groups, there are multiple different tools which help to work with and allows bot also to manage "Single-User" chats and group chats.

Splitter Form

An easy way to switch between a Single-User form and one for managing a group is the SplitterForm base class. It calls special methods which you can override and then move from there to the form you need.

The OpenGroup method is the backup if OpenChannel or OpenSupergroup is not overridden. Same for Open, it is "backup" if none of the previous methods has been overridden.

public class Start : SplitterForm
{
    public override async Task<bool> Open(MessageResult e)
    {
        var st = new Menu();
        await this.NavigateTo(st);

        return true;
    }

    public override async Task<bool> OpenGroup(MessageResult e)
    {
        var st = new Groups.LinkReplaceTest();
        await this.NavigateTo(st);

        return true;
    }

    public override Task<bool> OpenChannel(MessageResult e)
    {
        return base.OpenChannel(e);
    }

    public override Task<bool> OpenSupergroup(MessageResult e)
    {
        return base.OpenSupergroup(e);
    }
}

Group Form

For managing groups there's a base class called GroupForm. This one has special events which should make it easier to work with groups and channels. In the Example project there's a simple example for deleting an url written by a user and incrementing an internal counter. At every url he writes he gets blocked for a small amount of time and the message gets deleted. At 3 failures, the user gets kicked of the group and blocked.

public class GroupForm : FormBase
{
    public override async Task Load(MessageResult message)
    {
        switch (message.MessageType)
        {
            case Telegram.Bot.Types.Enums.MessageType.ChatMembersAdded:
                await OnMemberChanges(new MemberChangeEventArgs(Telegram.Bot.Types.Enums.MessageType.ChatMembersAdded, message, message.RawMessageData.Message.NewChatMembers));
                break;

            case Telegram.Bot.Types.Enums.MessageType.ChatMemberLeft:
                await OnMemberChanges(new MemberChangeEventArgs(Telegram.Bot.Types.Enums.MessageType.ChatMemberLeft, message, message.RawMessageData.Message.LeftChatMember));
                break;

            case Telegram.Bot.Types.Enums.MessageType.ChatPhotoChanged:
            case Telegram.Bot.Types.Enums.MessageType.ChatPhotoDeleted:
            case Telegram.Bot.Types.Enums.MessageType.ChatTitleChanged:
            case Telegram.Bot.Types.Enums.MessageType.MigratedFromGroup:
            case Telegram.Bot.Types.Enums.MessageType.MigratedToSupergroup:
            case Telegram.Bot.Types.Enums.MessageType.MessagePinned:
            case Telegram.Bot.Types.Enums.MessageType.GroupCreated:
            case Telegram.Bot.Types.Enums.MessageType.SupergroupCreated:
            case Telegram.Bot.Types.Enums.MessageType.ChannelCreated:
                await OnGroupChanged(new GroupChangedEventArgs(message.MessageType, message));
                break;

            default:
                OnMessage(message);
                break;
        }
    }

    public virtual async Task OnMemberChanges(MemberChangeEventArgs e)
    {
    }

    public virtual async Task OnGroupChanged(GroupChangedEventArgs e)
    {
    }

    public virtual async Task OnMessage(MessageResult e)
    {
    }
}

Statemachine and Sessions

Depending on the use-cases and the overall structure of a Telegram Bot, it is essential to have some kind of session serialization or state machine to keep the user context after bot restarts (i.e. due to updates) or crashes. For this, we have some structures which fit into the current environment.

Statemachines

There are actually 3 types of example state machines you could use. A state machine is a kind of serializer which saves the important session data in a reusable structure like JSON or XML.

SimpleJSONStateMachine

Is easy to use and useful for simple structures like basic datatypes. Won't work for complex ones like generics.

var bot = BotBaseBuilder
    .Create()
    .WithAPIKey("{YOUR API KEY}")
    .DefaultMessageLoop()
    .WithStartForm<StartForm>()
    .NoProxy()
    .CustomCommands(a =>
    {
        a.Start("Starts the bot");
    })
    .UseSimpleJSON(AppContext.BaseDirectory + "config\\states.json")
    .UseEnglish()
    .UseSingleThread()
    .Build();

await bot.Start();

JSONStateMachine

It is easy to use too, but it works for complex datatypes, because it saves their namespaces and additional type info into the JSON file.

var bot = BotBaseBuilder
    .Create()
    .WithAPIKey("{YOUR API KEY}")
    .DefaultMessageLoop()
    .WithStartForm<StartForm>()
    .NoProxy()
    .CustomCommands(a =>
    {
        a.Start("Starts the bot");
    })
    .UseJSON(AppContext.BaseDirectory + "config\\states.json")
    .UseEnglish()
    .UseSingleThread()
    .Build();

await bot.Start();

XMLStateMachine

The last one should work like the others.

var bot = BotBaseBuilder
    .Create()
    .WithAPIKey("{YOUR API KEY}")
    .DefaultMessageLoop()
    .WithStartForm<StartForm>()
    .NoProxy()
    .CustomCommands(a =>
    {
        a.Start("Starts the bot");
    })
    .UseXML(AppContext.BaseDirectory + "config\\states.xml")
    .UseEnglish()
    .UseSingleThread()
    .Build();

await bot.Start();

Interfaces

There are two interfaces, one for the StateMachine itself, which is useful to build a custom one for a different datatype and one for implementing into a form which should be invoked with events.

IStateMachine

Is the basic StateMachine interface, it has two methods SaveFormStates(SaveStatesEventArgs e) and LoadFormStates(), nothing fancy, just simple calls. Implement both methods with your own serialization process.

public interface IStateMachine
{
    void SaveFormStates(SaveStatesEventArgs e);

    StateContainer LoadFormStates();
}

IStateForm

When implemented, this will invoke one of these two methods: LoadState(LoadStateEventArgs e) or SaveState(SaveStateEventArgs e). They have methods to load or save data from the statemachine of the current form.

public interface IStateForm
{
    void LoadState(LoadStateEventArgs e);
    void SaveState(SaveStateEventArgs e);
}

Attributes

If you don't want to implement the IStateForm interface, because there are maybe just one or two properties you want to keep and restore, use the following attributes.

SaveState

This will let the engine know that you want to keep and restore this field automatically. Unlike the IStateForm methods, you have no option to manipulate data.

[SaveState]
public long UserId { get; set; }

IgnoreState

Due to the fact that Attribute implementation and interaction is optional, you want to let the engine maybe know that you don't want to keep a specific form. So it should get lost. This attribute will help you here, add it to the form class, and it will not get serialized, even if it implements IStateForm or the SaveState attributes.

[IgnoreState]
public class Registration : STForm
{
}

Navigation and NavigationController

As of now

As from earlier topics on this readme you already know the default way for (cross) navigation between Forms. It will look something like this:

var f = new FormBase();
await this.NavigateTo(f);

Depending on the model and structure of your bot, it can make sense, to have more linear navigation instead of cross-navigation.

For example, you have a bot which shows a list of football teams. And when clicking on it, you want to open the team details and the latest matches.

After the matches, you want to maybe switch to different teams and take a look at their statistics and matches.

At some point, you just want to get back to the first team, so like on Android you're clicking the "back" button multiple times.

This can become really complicated, when not having some controller below which handle these "Push/Pop" calls.

That's why we have a NavigationController class which manages these situations and the stack.

Usage

First, you need to create a NavigationController instance at the same position in code, where you want to start the navigation.

You will use the current FormBase instance as a root class within the constructor, so you can later come back to this one.

Tip: You can also add a completely new instance of i.e. a main menu form here to get back to it then. So you are free to choose.

We are using the same FormBase instance as above.

var nc = new NavigationController(this);
var f = new FormBase();

// Replace the current form in the context with the controller.
await this.NavigateTo(nc);

// Push the new from onto the stack to render it
nc.PushAsync(f);

Later to open a new form use PushAsync again:

await this.NavigationController.PushAsync(newForm);

When you want to go back one Form on the stack use PopAsync:

await this.NavigationController.PopAsync();

Notice: By default the NavigationController has ForceCleanupOnLastPop enabled, which means that when the stack is again at 1 (due to PopAsync or PopToRootAsync calls) it will replace the controller automatically with the root form you have given to the constructor at the beginning.


Extensions

TelegramBotBase.Extensions.Images

Extends the base package with some additional image methods like SendPhoto (using Bitmap)

NuGet version (TelegramBotBase) Downloads

Source code: TelegramBotBase.Extensions.Images/

Nuget package: https://www.nuget.org/packages/TelegramBotBase.Extensions.Images/


TelegramBotBase.Extensions.Images.IronSoftware

Extends the base package with some additional image methods like SendPhoto (using Bitmap)

Important: This extension uses the IronSoftware drawing library.

NuGet version (TelegramBotBase) Downloads

https://www.nuget.org/packages/TelegramBotBase.Extensions.Images.IronSoftware/

Source code: TelegramBotBase.Extensions.Images.IronSoftware/

Nuget package: https://www.nuget.org/packages/TelegramBotBase.Extensions.IronSoftware/


Project: open source

TelegramBotBase.Extensions.Images.IronSoftware

Extends the base package with some additional image methods like SendPhoto (using Bitmap)

Important: This extension uses the IronSoftware drawing library.

NuGet version (TelegramBotBase) Downloads

https://www.nuget.org/packages/TelegramBotBase.Extensions.Images.IronSoftware/

Project: open source

TelegramBotBase.Extensions.Serializer.Database.MSSQL

A session serializer for Microsoft SQL Server.

NuGet version (TelegramBotBase) Downloads

Source code: TelegramBotBase.Extensions.Serializer.Database.MSSQL/

Nuget package: https://www.nuget.org/packages/TelegramBotBase.Extensions.Serializer.Database.MSSQL/


TelegramBotBase.Extensions.Serializer.Database.PostgreSql

A session serializer for PostgreSql Server.

NuGet version (TelegramBotBase) Downloads

Source code: TelegramBotBase.Extensions.Serializer.Database.PostgreSql/

Nuget package: https://www.nuget.org/packages/TelegramBotBase.Extensions.Serializer.Database.PostgreSql/

Credits: @Kataane


Project: open source

Test Project

There is a "TelegramBotBase.Test" project inside the repository which includes minimal examples for all controls available. Check it out to get a brief overview about all possibilities.

Examples

You can find all example projects in the "Examples" subfolder.

Will allow you to run specific system commands or run/kill processes via Bot. Also has a simple authentication mechanism with one password.

Example using minimal dotnet console template with EntityFramework and Dependency Injection.

Will delete Join and Leave messages automatically in groups.

When you want to update forms async without any user interaction (message/action) before. Use the new InvokeMessageLoop method of BotBase.

Having already a web application and want to add a TelegramBot side-by-side with it running ? Here is an example how you could do it.

Want to use Inline- and ReplyMarkup at the same time ? Here is an example how you can do that:

Alpha: Full Dependency Injection example within this framework.