Skip to content

Commit

Permalink
chore: Code refinement, example updates, and documentation enhancement
Browse files Browse the repository at this point in the history
- Code cleanup.
- Updated example projects.
- Enhanced documentation to reflect recent feature additions.
  • Loading branch information
Eptagone committed Jan 8, 2024
1 parent da12baf commit ce26d7b
Show file tree
Hide file tree
Showing 255 changed files with 3,556 additions and 3,178 deletions.
81 changes: 64 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ It contains all the methods and types available in the Bot API 7.0 released on D
## .NET platforms support

- NET Standard >= 2.0
- NET Core >= 2.0, .NET 5|6|7
- NET Core >= 2.0, .NET 6, .NET 8
- NET Framework >= 4.6.2
- Universal Windows Platform >= 10.0.16299
- Unity >= 2018.1
Expand All @@ -43,14 +43,14 @@ dotnet add PROJECT package Telegram.BotAPI

## How to use

First, get your **bot token** from [BotFather](https://t.me/BotFather) and use it to create a new instance of `Telegram.BotAPI.BotClient` as follows.
First, get your **bot token** from [BotFather](https://t.me/BotFather) and use it to create a new instance of `Telegram.BotAPI.TelegramBotClient` as follows.

```CSharp
using Telegram.BotAPI;

var botToken = "bot123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11";
// You need a BotClient instance if you want access to the Bot API methods.
var api = new BotClient(botToken);
// You need a TelegramBotClient instance if you want access to the Bot API methods.
var client = new TelegramBotClient(botToken);
```

The methods and types are organized in namespaces according to their corresponding section on the [Official Bot API website](https://core.telegram.org/bots/api). So if you want to use a method or type, you must first include the corresponding namespace.
Expand All @@ -59,7 +59,7 @@ Currently the following namespaces are available:

| Name | Description |
| :------------------------------- | :----------------------------------------------- |
| Telegram.BotAPI | Contains the BotClient and other utilities |
| Telegram.BotAPI | Contains the TelegramBotClient and other utilities |
| Telegram.BotAPI.GettingUpdates | Contains methods and types for getting updates |
| Telegram.BotAPI.AvailableTypes | Contains available types |
| Telegram.BotAPI.AvailableMethods | Contains available methods |
Expand All @@ -70,20 +70,20 @@ Currently the following namespaces are available:
| Telegram.BotAPI.TelegramPassport | Contains methods and types for Telegram Passport |
| Telegram.BotAPI.Games | Contains methods and types for games |

Once the namespaces are included, you are ready to start managing your bot. For example, you can use the [getMe](https://core.telegram.org/bots/api#sendmessage) method to get basic information about your bot.
Once the namespaces are included, you are ready to start managing your bot. For example, you can use the [getMe](https://core.telegram.org/bots/api#getme) method to get basic information about your bot.

```CSharp
using Telegram.BotAPI.AvailableMethods;

var me = api.GetMe();
var me = client.GetMe();
Console.WriteLine("My name is {0}.", me.FirstName);
```

## Getting updates

Every time a user interacts with a bot, bot will receive a new update. Updates contain information about user events, such as a new message or when a button is clicked. If you want your bot to reply to a message, then your bot must be able to get updates first.

Currently, there are two ways to get updates: [Long Polling](###Long-Polling) and [webhooks](###Webhooks).
Currently, there are two ways to get updates: [Long Polling](#long-polling) and [webhooks](#webhooks).

### Long Polling

Expand All @@ -93,7 +93,7 @@ To get updates using **Long Polling**, you must create a perpetual loop and chec
using System.Linq;
using Telegram.BotAPI.GettingUpdates;

var updates = api.GetUpdates();
var updates = client.GetUpdates();
while (true)
{
if (updates.Any())
Expand All @@ -103,11 +103,11 @@ while (true)
// Process update
}
var offset = updates.Last().UpdateId + 1;
updates = api.GetUpdates(offset);
updates = client.GetUpdates(offset);
}
else
{
updates = api.GetUpdates();
updates = client.GetUpdates();
}
}
```
Expand All @@ -120,12 +120,16 @@ To receive updates through webhook, you must create a web application. In your A
using Telegram.BotAPI.GettingUpdates;

[HttpPost]
public IActionResult Post([FromBody] Update update)
public IActionResult Post(
// The secret token is optional, but it's highly recommended to use it.
[FromHeader(Name = "X-Telegram-Bot-Api-Secret-Token")] string secretToken,
[FromBody] Update update)
{
if (update == null)
if (update is null)
{
return BadRequest();
}
// Check if the secret token is valid
// Process your update
return Ok();
}
Expand All @@ -138,9 +142,8 @@ api.DeleteWebhook(true); // Delete old webhook
api.SetWebhook("https://example.com/<controller path>"); // Set new webhook
```

> It's high recommended to use a secret path to access the api controller.
> Using webhook will disable the `getUpdates` method. Use `deleteWebhook` to enable it again.
> It's high recommended to configurate a secret token to access the api controller through the setWebhook method. This will prevent third parties from accessing your api controller.
> Using a webhook will disable the `getUpdates` method. Use `deleteWebhook` to enable it again.
## Sending messages

Expand All @@ -157,7 +160,7 @@ Your bot can also send multimedia messages like photos, gifs, videos, and others

## Uploading files

You can send attached files using InputFile objects. You have two ways to do it.
You can also send attached files using InputFile objects. You have two ways to do it: By using an InputFile object directly or by using an AttachedFile object.

### Option 1

Expand Down Expand Up @@ -187,6 +190,50 @@ var files = new AttachedFile[]
api.SendDocument(chatId, "attach://file56", attachedFiles: files);
```

## Making custom requests

The library already includes all types and methods available in the Bot API. However, if you want to use your own types or if you want to be the first one to use new features when they are released, you can use the `CallMethod` and/or `CallMethodDirect` methods defined in the ITelegramBotClient instance.

```CSharp
var args = new Dictionary<string, object>() {
{ "chat_id", 123456789 },
{ "text", "Hello World!" }
};
// Message is the type you want to use to deserialize the response result. It can be an in-built type or a custom type created by you.
var message = client.CallMethod<Message>("sendMessage", args);
```

The previous method is used by all extension methods defined in the library. You can also create your own extension methods to make custom requests if you want.

```CSharp
public static class TelegramBotClientExtensions
{
public static Message SendHelloWorld(this ITelegramBotClient client, long chatId)
{
var args = new Dictionary<string, object>() {
{ "chat_id", chatId },
{ "text", "Hello World!" }
};
return client.CallMethod<Message>("sendMessage", args);
}
}
```

The library also includes the classes `MethodNames` and `PropertyNames` that contain the names of all methods and properties.

The `CallMethod` will trigger an exception if the response status code is not OK. If you don't like this behavior, you can use the `CallMethodDirect` method instead.

```CSharp
var args = new Dictionary<string, object>() {
{ "chat_id", 123456789 },
{ "text", "Hello World!" }
};
// BotResponse<Message>
var response = client.CallMethodDirect<Message>("sendMessage", args);
```

You'll get a `BotResponse<T>` object as a response. This object contains the status code, the deserialized result or null (if error), the error description and also some error parameters if available.

---

## Examples
Expand Down
5 changes: 4 additions & 1 deletion src/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ csharp_style_prefer_not_pattern = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_var_when_type_is_apparent = false:silent
csharp_style_var_elsewhere = false:silent
csharp_style_prefer_primary_constructors = true:suggestion
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent

[*.{cs,vb}]
dotnet_diagnostic.CA1707.severity=suggestion
Expand Down Expand Up @@ -111,7 +114,7 @@ dotnet_style_object_initializer = true:suggestion
dotnet_style_operator_placement_when_wrapping = beginning_of_line
tab_width = 4
indent_size = 4
end_of_line = crlf
end_of_line = lf
dotnet_style_collection_initializer = true:suggestion
dotnet_style_qualification_for_field = true:suggestion
dotnet_style_qualification_for_property = true:suggestion
Expand Down
3 changes: 2 additions & 1 deletion src/examples/BotTemplate/BotTemplateSample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\Telegram.BotAPI\Telegram.BotAPI.csproj" />
<ProjectReference Include="..\..\library\Telegram.BotAPI\Telegram.BotAPI.csproj" />
<ProjectReference Include="..\..\library\Telegram.BotAPI.Extensions\Telegram.BotAPI.Extensions.csproj" />
</ItemGroup>

</Project>
50 changes: 21 additions & 29 deletions src/examples/BotTemplate/MyBot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,19 @@
using Telegram.BotAPI;
using Telegram.BotAPI.AvailableMethods;
using Telegram.BotAPI.AvailableTypes;
using Telegram.BotAPI.Extensions;
using Telegram.BotAPI.GettingUpdates;

namespace BotTemplateSample
{
public sealed class MyBot : TelegramBotBase
public sealed class MyBot : SimpleTelegramBotBase
{
public static readonly BotClient Bot = new("<BOT TOKEN>");
public static readonly TelegramBotClient Bot = new("<BOT TOKEN>");
public static readonly User Me = Bot.GetMe();

private Message message;
private bool hasText;
private User appUser;

public override void OnUpdate(Update update)
{
Console.WriteLine("New update with id: {0}. Type: {1}", update?.UpdateId, update?.Type.ToString("F"));
Console.WriteLine("New update with id: {0}. Type: {1}", update?.UpdateId, update.GetUpdateType());
base.OnUpdate(update);
}

Expand All @@ -33,49 +30,44 @@ protected override void OnMessage(Message message)
{
return;
}
Console.WriteLine("New message from chat id: {0}", message.Chat.Id);

this.appUser = message.From; // Save current user;
this.message = message; // Save current message;
this.hasText = !string.IsNullOrEmpty(message.Text); // True if message has text;

Console.WriteLine("Message Text: {0}", this.hasText ? message.Text : "|:O");
Console.WriteLine("New message from chat id: {0}", message.Chat.Id);
Console.WriteLine("Message Text: {0}", message.Text ?? "|:O");

if (message.Chat.Type == ChatType.Private) // Private Chats
{
// Make something
}
else // Group chats
{

}
if (this.hasText)
// Check if the message contains a command
if (message.Entities.Any(e => e.Type == "bot_command"))
{
if (message.Text.StartsWith('/')) // New commands
// If the command includes a mention, you should verify that it is for your bot, otherwise you will need to ignore the command.
var pattern = string.Format(@"^\/(?<COMMAND>\w*)(?:|@{0})(?:$|\s(?<PARAMETERS>.*))", Me.Username);
var match = Regex.Match(message.Text, pattern, RegexOptions.IgnoreCase);
if (match.Success)
{
// If the command includes a mention, you should verify that it is for your bot, otherwise you will need to ignore the command.
var pattern = string.Format(@"^\/(?<COMMAND>\w*)(?:|@{0})(?:$|\s(?<PARAMETERS>.*))", Me.Username);
var match = Regex.Match(message.Text, pattern, RegexOptions.IgnoreCase);
if (match.Success)
{
var command = match.Groups.Values.Single(v => v.Name == "COMMAND").Value; // Get command name
var @params = match.Groups.Values.SingleOrDefault(v => v.Name == "PARAMETERS")?.Value; // Get command params
var parameters = @params?.Split(' ').Where(s => !string.IsNullOrEmpty(s)).ToArray();
var command = match.Groups.Values.Single(v => v.Name == "COMMAND").Value; // Get command name
var @params = match.Groups.Values.SingleOrDefault(v => v.Name == "PARAMETERS")?.Value;

Console.WriteLine("New command: {0}", command);
this.OnCommand(command, parameters);
}
Console.WriteLine("New command: {0}", command);
this.OnCommand(message, command, @params);
}
}
}

private void OnCommand(string cmd, string[] args)
protected override void OnCommand(Message message, string cmd, string parameters)
{
var args = parameters.Split(' ', StringSplitOptions.RemoveEmptyEntries);
Console.WriteLine("Params: {0}", args.Length);
switch (cmd)
{
case "hello":
var hello = string.Format("Hello World, {0}!", this.appUser.FirstName);
Bot.SendMessage(this.message.Chat.Id, hello);
var hello = string.Format("Hello World, {0}!", message.From.FirstName);
Bot.SendMessage(message.Chat.Id, hello);
break;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/examples/BotTemplate/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace BotTemplateSample
}
public sealed class MyBot : TelegramBot
{
public static BotClient Bot = new BotClient("<your bot token>");
public static TelegramBotClient Bot = new TelegramBotClient("<your bot token>");
public static User Me = Bot.GetMe();
public static void StartPolling()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\Telegram.BotAPI\Telegram.BotAPI.csproj" />
<ProjectReference Include="..\..\library\Telegram.BotAPI\Telegram.BotAPI.csproj" />
</ItemGroup>

</Project>
43 changes: 20 additions & 23 deletions src/examples/Callback query button 01/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ static void Main()
{
Console.WriteLine("Start!");

var bot = new BotClient("<your bot token>");
var bot = new TelegramBotClient("<your bot token>");
bot.SetMyCommands(new BotCommand("callback", "new callback"));

// Long Polling
Expand All @@ -28,32 +28,29 @@ static void Main()
{
foreach (var update in updates)
{
switch (update.Type)
if (update.Message != null)
{
case UpdateType.Message:
var message = update.Message;
if (message.Text.Contains("/callback"))
var message = update.Message;
if (message.Text.Contains("/callback"))
{
var replyMarkup = new InlineKeyboardMarkup
{
var replyMarkup = new InlineKeyboardMarkup
{
InlineKeyboard = new InlineKeyboardButton[][]{
new InlineKeyboardButton[]{
InlineKeyboardButton.SetCallbackData("Callback", "callback_data")
InlineKeyboard = new InlineKeyboardButton[][]{
new InlineKeyboardButton[] {
new("Callback") {
CallbackData = "callback_data"
}
}
};
bot.SendMessage(message.Chat.Id, "Message with callback data", replyMarkup: replyMarkup);
}
break;
case UpdateType.CallbackQuery:
var query = update.CallbackQuery;
bot.AnswerCallbackQuery(query.Id, "HELLO");
bot.EditMessageText(new EditMessageTextArgs($"Click!\n\n{query.Data}")
{
ChatId = query.Message.Chat.Id,
MessageId = query.Message.MessageId
});
break;
}
};
bot.SendMessage(message.Chat.Id, "Message with callback data", replyMarkup: replyMarkup);
}
}
else if (update.CallbackQuery != null)
{
var query = update.CallbackQuery;
bot.AnswerCallbackQuery(query.Id, "HELLO");
bot.EditMessageText(query.Message.Chat.Id, query.Message.MessageId, $"Click!\n\n{query.Data}");
}
}
updates = updates = bot.GetUpdates(offset: updates.Max(u => u.UpdateId) + 1);
Expand Down
2 changes: 1 addition & 1 deletion src/examples/Callback query button 01/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace CallbackQueryButton01
static void Main()
{
Console.WriteLine("Start!");
var bot = new BotClient("<your bot token>");
var bot = new TelegramBotClient("<your bot token>");
bot.SetMyCommands(new BotCommand("callback", "new callback"));
var updates = bot.GetUpdates();
while (true)
Expand Down
2 changes: 1 addition & 1 deletion src/examples/Examples.sln
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{7A
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Library", "Library", "{ADD476C3-7C77-421E-8A5F-F5DC41886727}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Telegram.BotAPI", "..\Telegram.BotAPI\Telegram.BotAPI.csproj", "{7885DD73-1782-4D0E-826E-C60C27C7648D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Telegram.BotAPI", "..\library\Telegram.BotAPI\Telegram.BotAPI.csproj", "{7885DD73-1782-4D0E-826E-C60C27C7648D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloBotNET.AppService", "HelloBotNET.AppService\HelloBotNET.AppService.csproj", "{40F07F65-6DF5-48D2-9C11-0D970BFA31A0}"
EndProject
Expand Down
Loading

0 comments on commit ce26d7b

Please sign in to comment.