-
Notifications
You must be signed in to change notification settings - Fork 0
Getting started
Framework uses Autofac as common Dependency Injection container, so whole services should be reigstered with it. If you're not familiar with it, please, check its documentation.
Framework processes not a whole Update, only it's part (e.g. Message, CallbackQuery, InlineQuery), which called Entity and that's means you could register handlers for each type of update.
IHandlerContext<TEntity>, where TEntity is Message, CallbackQuery, or any available type, which Update object has, - is the general interface, which holds common information about entity, such as update object, this entity taken from, update sender (User who send this entity, could be null, if entity doesn't have From field), Container, which is Autofac's IContainer interface, which is using for resolving types and services, if built-in service injection doesn't suit you.
Entity handler structure should be like this:
[YourCustomHandlerAttribute(...)]
public ReturnType MyCoolEntityHandler(IHandlerContext<TEntity> handlerContext, TService1 requiredService1, TService2 requiredService2)
{
//Your handler logic here
}Where:
-
YourCustomHandlerAttribute- attribute, which allows current method to be registered in entity processing pipeline. Inherited fromUpdateEntityHandlerAttributeBase -
ReturnTypeisbool, orTask<bool>, orValueTask<bool>. -
TService1,TService2- services you needed in, which are contained in Autofac'sIContainer. Otherwise, if services aren't represented in dependency injection container,requiredService1andrequiredService2will equals tonull.
Handler return value indicates, should be next entity handler be invoked, or not, so, to continue handling, you should write return true, otherwise, logically, return false.
Here we will use classes, attributes, and extension methods from here.
Firstly, let's define some constant, which we will use as an identifier for entity handlers and entity builder of which is related to Message processing:
public string const MessagesEntityProcessorId = "Messages";Then, let's define our first entity handler, which will process Messages.
[MessageEntityHandlerAttribute(position: 1)] //Marks this handler to be invoked first.
public async bool CheckMessageTextForHelloHandler(IHandlerContext<Message> messageHandlerContext)
{
string text = messageHandlerContext.Entity.Text; //Entity - Message object
if(text.Contains("hello"))
{
return true;
}
return false;
}Where MessageEntityHandlerAttribute is:
public class MessageEntityHandlerAttribute : PositionedEntityHandlerAttribute
{
public MessageEntityHandlerAttribute(int position) : base(position, MessagesEntityProcessorId, UpdateType.Message)
{
}
}[MessageEntityHandlerAttribute(position: 1)]
public Task<bool> CheckMessageTextForHelloHandler(IHandlerContext<Message> messageHandlerContext, ITextMatcherService textMatcherService)
{
string text = messageHandlerContext.Entity.Text; //Entity - Message object
return textMatcherService.CheckThatMessageTextMatchSomeCriteria(text);
}Where ITextMatcherService is:
public interface ITextMatcherService
{
Task<bool> CheckThatMessageTextMatchSomeCriteria(string messageText);
}And realization of this interface:
public class TextMatcherService : ITextMatcherService
{
private const string RequiredTextInMessage = "hello";
public async Task<bool> CheckThatMessageTextMatchSomeCriteria(string messageText)
{
return messageText.Contains(RequiredTextInMessage);
}
}Register service with Autofac's ContainerBuilder:
ContainerBuilder containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<TextMatcherService>().As<ITextMatcherService>();To configure and build bot instance, you should use BotBuilder class:
string botName = "Spire Example Bot"; //Defining bot name.
ITelegramBotClient telegramBotClient = new TelegramBotClient("Your Bot Api Token here"); //Creating telegram bot client instance.
IContainer container = containerBuilder.Build(); //Building previously configured ContainerBuilder.
IBotBuilder botBuilder = new BotBuilder(botName, telegramBotClient, container);Then, lets assume our CheckMessageTextForHelloHandler is container in CheckMessageTextForHelloHandlerSource type:
public class CheckMessageTextForHelloHandlerSource
{
[MessageEntityHandlerAttribute(position: 1)]
public Task<bool> CheckMessageTextForHelloHandler(IHandlerContext<Message> messageHandlerContext, ITextMatcherService textMatcherService)
{
string text = messageHandlerContext.Entity.Text; //Entity - Message object
return textMatcherService.CheckThatMessageTextMatchSomeCriteria(text);
}
}Then, registration of this handler will be like this:
botBuilder.WithPositionedUpdateEntityProcessorBuilder<Message>(
MessagesEntityProcessorId,
UpdateType.Message,
updateEntityProcessorBuilder => updateEntityProcessorBuilder
.WithUpdateEntityHandlersFromType(typeof(CheckMessageTextForHelloHandlerSource))WithUpdateEntityHandlersFromType will scan type for methods, available for registering in entity processing pipeline.
Also, there is WithUpdateEntityHandlersFromAssembly methos, which scans specified assembly for exported types, and calls WithUpdateEntityHandlersFromType for each of them.
Note, we will use console hosting framework part here.
After all steps, specified below, our project will be like this:
Program.cs:
using Autofac;
using Spire;
using Spire.Core.Abstractions;
using Spire.Core.Abstractions.Builders;
using Spire.Core.Builders;
using Spire.Hosting;
using Spire.Hosting.Console;
using Telegram.Bot;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
using ExampleBot.Services; //TextMatcherService and ITextMatcherService definitions.
namespace ExampleBot
{
class Program
{
static void Main(string[] args)
{
ConsoleBotHost consoleBotHost = ConsoleBotHost
.CreateDefault(args)
.WithBot(BuildExampleBot);
consoleBotHost.Run(); //Runs bot in LongPolling mode.
while(true) { }
}
static IBot BuildExampleBot(BotConfigurationOptions consoleBotConfigurationOptions)
{
ContainerBuilder containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<TextMatcherService>().As<ITextMatcherService>();
IContainer container = containerBuilder.Build();
ITelegramBotClient telegramBotClient = new TelegramBotClient(consoleBotConfigurationOptions.ApiToken);
IBotBuilder botBuilder = new BotBuilder(consoleBotConfigurationOptions.Name, telegramBotClient, container);
botBuilder.WithPositionedUpdateEntityProcessorBuilder<Message>(
DefaultProcessorId,
UpdateType.Message,
messageEntityProcessorBuilder => messageEntityProcessorBuilder
.WithUpdateEntityHandlersFromType(typeof(CheckMessageTextForHelloHandlerSource)));
return botBuilder.Build();
}
}
}Services/ITextMatcherService.cs:
using System.Threading.Tasks;
namespace ExampleBot.Services
{
public interface ITextMatcherService
{
Task<bool> CheckThatMessageTextMatchSomeCriteria(string messageText);
}
}Services/TextMatcherService.cs:
using System.Threading.Tasks;
namespace ExampleBot.Services
{
public class TextMatcherService : ITextMatcherService
{
private const string RequiredTextInMessage = "hello";
public async Task<bool> CheckThatMessageTextMatchSomeCriteria(string messageText)
{
return messageText.Contains(RequiredTextInMessage);
}
}
}MessageEntityHandlerAttribute.cs:
using Spire;
namespace ExampleBot
{
public class MessageEntityHandlerAttribute : PositionedEntityHandlerAttribute
{
public MessageEntityHandlerAttribute(int position) : base(position, MessagesEntityProcessorId, UpdateType.Message)
{
}
}
}CheckMessageTextForHelloHandlerSource.cs:
using System.Threading.Tasks;
using Spire.Core.Abstractions.Processing.Contexts;
using Telegram.Bot.Types;
using ExampleBot.Services;
namespace ExampleBot
{
public class CheckMessageTextForHelloHandlerSource
{
[MessageEntityHandlerAttribute(position: 1)]
public Task<bool> CheckMessageTextForHelloHandler(IHandlerContext<Message> messageHandlerContext,
ITextMatcherService textMatcherService)
{
string text = messageHandlerContext.Entity.Text;
return textMatcherService.CheckThatMessageTextMatchSomeCriteria(text);
}
}
}