From 3094fcbabe2cce58f701653370fffe7788d63810 Mon Sep 17 00:00:00 2001 From: Dmitri Shimanski Date: Fri, 21 Mar 2025 00:49:01 +0200 Subject: [PATCH] Fix error with broken dependencies. --- Examples/Telegram.Examples/Program.cs | 16 +- .../Telegram.Examples.csproj | 3 + .../Telegram.Examples/UpdatePolling/Update.cs | 14 +- Examples/Telegram.Examples/appsettings.json | 4 + README.md | 16 +- .../Services/TelegramHostedService.cs | 157 +++++++----------- Telegram.Net/Telegram.Net.csproj | 2 +- 7 files changed, 108 insertions(+), 104 deletions(-) create mode 100644 Examples/Telegram.Examples/appsettings.json diff --git a/Examples/Telegram.Examples/Program.cs b/Examples/Telegram.Examples/Program.cs index 1f2436a..541b4dd 100644 --- a/Examples/Telegram.Examples/Program.cs +++ b/Examples/Telegram.Examples/Program.cs @@ -1,4 +1,5 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Telegram.Net; @@ -7,12 +8,11 @@ var webHost = Host.CreateDefaultBuilder() .ConfigureLogging(l => l.ClearProviders().AddConsole()) .ConfigureServices(k => { - k.ConnectTelegram(new("TOKEN") - { - errorHandler = async (client, exception, ctx) => - { - Console.WriteLine(exception); - } - }); + var _conf = new ConfigurationBuilder() + .AddJsonFile("appsettings.json") + .AddEnvironmentVariables() + .Build(); + k.AddSingleton(_conf); + k.ConnectTelegram(new(_conf.GetValue("telegram_test_token"))); }); webHost.Build().Run(); \ No newline at end of file diff --git a/Examples/Telegram.Examples/Telegram.Examples.csproj b/Examples/Telegram.Examples/Telegram.Examples.csproj index 2891280..89f1238 100644 --- a/Examples/Telegram.Examples/Telegram.Examples.csproj +++ b/Examples/Telegram.Examples/Telegram.Examples.csproj @@ -11,6 +11,9 @@ + + + diff --git a/Examples/Telegram.Examples/UpdatePolling/Update.cs b/Examples/Telegram.Examples/UpdatePolling/Update.cs index f6c703c..1d55ec6 100644 --- a/Examples/Telegram.Examples/UpdatePolling/Update.cs +++ b/Examples/Telegram.Examples/UpdatePolling/Update.cs @@ -1,4 +1,5 @@ -using Telegram.Bot; +using Microsoft.Extensions.Configuration; +using Telegram.Bot; using Telegram.Bot.Types; using Telegram.Net.Attributes; using Telegram.Net.Interfaces; @@ -7,6 +8,11 @@ namespace Telegram.Examples.UpdatePolling; public class Update : IUpdatePollingService { + private static IConfiguration _conf; + public Update(IConfiguration conf) + { + _conf = conf; + } [Update] public async Task UpdateExample(ITelegramBotClient client, Bot.Types.Update update, CancellationToken ctx) { @@ -31,6 +37,12 @@ public class Update : IUpdatePollingService await client.SendMessage(message.From!.Id, "Hello, I`m example bot.", cancellationToken: ctx); } + [Command("/test_conf")] + public async Task TestConfigurationBuilder(ITelegramBotClient client, Message message, CancellationToken cts) + { + await client.SendMessage(message.Chat.Id, _conf.GetValue("ExampleMessage") ?? throw new Exception("Not found")); + } + [EditMessage] public async Task EditMessageExmaple(ITelegramBotClient client, Message message, CancellationToken ctx) { diff --git a/Examples/Telegram.Examples/appsettings.json b/Examples/Telegram.Examples/appsettings.json new file mode 100644 index 0000000..58bbea0 --- /dev/null +++ b/Examples/Telegram.Examples/appsettings.json @@ -0,0 +1,4 @@ +{ + "ExampleMessage": "Test!", + "telegram_test_token": "PROVIDE_TOKEN" +} \ No newline at end of file diff --git a/README.md b/README.md index 9d519e8..99f371b 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,20 @@ Ensure you have the required dependencies installed: ## Usage +### Provide dependencies in class +You can provide dependencies in class from constructor, and after it use it like `static`. +```csharp +public class Example : IUpdatePollingService +{ + private static MyCoolService _service; // It should to be static! + + public Example(MyCoolService service) + { + _service = service; + } +} +``` + ### Inline Query Handling Use the `InlineAttribute` to register a method as an inline query handler. @@ -87,4 +101,4 @@ public static async Task HandleUpdate(ITelegramBotClient bot, Update update, Can ``` ## License -This project is open-source and available under the MIT License. \ No newline at end of file +This project is open-source and available under the [Apache 2.0 license](LICENSE) \ No newline at end of file diff --git a/Telegram.Net/Services/TelegramHostedService.cs b/Telegram.Net/Services/TelegramHostedService.cs index 846298c..11c786b 100644 --- a/Telegram.Net/Services/TelegramHostedService.cs +++ b/Telegram.Net/Services/TelegramHostedService.cs @@ -9,6 +9,8 @@ using Telegram.Bot.Types; using Telegram.Bot.Types.Payments; using Telegram.Net.Attributes; using Telegram.Net.Interfaces; +using static System.Reflection.BindingFlags; + #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously namespace Telegram.Net.Services; @@ -73,116 +75,85 @@ public class TelegramHostedService : IHostedService } } - + + + internal async Task AddAttributes(CancellationToken cancellationToken) { await Task.Run(async () => { try { - var implementations = AppDomain.CurrentDomain.GetAssemblies() + var attributeTypes = new HashSet + { + typeof(CommandAttribute), + typeof(CallbackAttribute), + typeof(EditMessageAttribute), + typeof(InlineAttribute), + typeof(PreCheckoutAttribute), + typeof(UpdateAttribute) + }; + + var methods = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(a => a.GetTypes()) - .Where(t => typeof(IUpdatePollingService).IsAssignableFrom(t) && !t.IsInterface); + .Where(t => typeof(IUpdatePollingService).IsAssignableFrom(t) && !t.IsInterface) + .SelectMany(t => t.GetMethods(Instance | + Public | + NonPublic | + DeclaredOnly)) + .Where(m => m.GetCustomAttributes().Any(a => attributeTypes.Contains(a.GetType()))) + .ToList(); - foreach (var implementation in implementations) + if (methods.Count == 0) { - isc.AddScoped(implementation); - } - - var methods = implementations - .SelectMany(t => t.GetMethods( - BindingFlags.Instance | - BindingFlags.Public | BindingFlags.NonPublic | - BindingFlags.DeclaredOnly)) - .Where(m => - m.GetCustomAttribute() != null || - m.GetCustomAttribute() != null || - m.GetCustomAttribute() != null || - m.GetCustomAttribute() != null || - m.GetCustomAttribute() != null || - m.GetCustomAttribute() != null); - - if (methods.Count() == 0) - { - _logger.LogWarning("Not founded methods with attributes."); + _logger.LogWarning("No methods found with required attributes"); } - await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); + var isp = isc.BuildServiceProvider(); foreach (var method in methods) { - var commandAttr = method.GetCustomAttribute(); - if (commandAttr != null) - { - if (IsValidHandlerMethod(method, typeof(Message))) - { - var handler = CreateDelegate(method); - if (!CommandHandler.TryAdd(commandAttr.Command, handler)) - throw new Exception($"Failed to add in commandHandler: {commandAttr.Command}"); - } + var declaringType = method.DeclaringType!; + var constructor = declaringType.GetConstructors()[0]; + var parameters = constructor.GetParameters() + .Select(param => isp.GetRequiredService(param.ParameterType)) + .ToArray(); + + constructor.Invoke(parameters); - continue; + void AddHandler(Dictionary> dictionary, string key) where T : class + { + if (!IsValidHandlerMethod(method, typeof(T))) return; + + var handler = CreateDelegate(method); + if (!dictionary.TryAdd(key, handler)) + throw new Exception($"Failed to add {key} to {dictionary.GetType().Name}"); } - var callbackAttr = method.GetCustomAttribute(); - if (callbackAttr != null) + switch (method.GetCustomAttributes().FirstOrDefault()) { - if (IsValidHandlerMethod(method, typeof(CallbackQuery))) - { - var handler = CreateDelegate(method); - if (!CallbackQueryHandler.TryAdd(callbackAttr.QueryId, handler)) - throw new Exception($"Failed to add in callbacKQuery: {callbackAttr.QueryId}");; - } - - continue; - } - - var editMessageAttr = method.GetCustomAttribute(); - if (editMessageAttr != null) - { - if (IsValidHandlerMethod(method, typeof(Message))) - { - var handler = CreateDelegate(method); - EditedMessageHandler.Add(handler); - } - - continue; - } - - var inlineAttr = method.GetCustomAttribute(); - if (inlineAttr != null) - { - if (IsValidHandlerMethod(method, typeof(InlineQuery))) - { - var handler = CreateDelegate(method); - if (!InlineHandler.TryAdd(inlineAttr.InlineId, handler)) - throw new Exception($"Failed to add in inlineHandler: {inlineAttr.InlineId}");; - } - - continue; - } - - var preCheckoutAttr = method.GetCustomAttribute(); - if (preCheckoutAttr != null) - { - if (IsValidHandlerMethod(method, typeof(PreCheckoutQuery))) - { - var handler = CreateDelegate(method); - PreCheckoutHandler = handler; - } - - continue; - } - - var updateAttr = method.GetCustomAttribute(); - if (updateAttr != null) - { - if (IsValidHandlerMethod(method, typeof(Update))) - { - var handler = CreateDelegate(method); - DefaultUpdateHandler.Add(handler); - } - - continue; + case CommandAttribute command: + AddHandler(CommandHandler, command.Command); + break; + + case CallbackAttribute callback: + AddHandler(CallbackQueryHandler, callback.QueryId); + break; + + case EditMessageAttribute _ when IsValidHandlerMethod(method, typeof(Message)): + EditedMessageHandler.Add(CreateDelegate(method)); + break; + + case InlineAttribute inline: + AddHandler(InlineHandler, inline.InlineId); + break; + + case PreCheckoutAttribute _ when IsValidHandlerMethod(method, typeof(PreCheckoutQuery)): + PreCheckoutHandler = CreateDelegate(method); + break; + + case UpdateAttribute _ when IsValidHandlerMethod(method, typeof(Update)): + DefaultUpdateHandler.Add(CreateDelegate(method)); + break; } } } diff --git a/Telegram.Net/Telegram.Net.csproj b/Telegram.Net/Telegram.Net.csproj index f612b35..9c0eba6 100644 --- a/Telegram.Net/Telegram.Net.csproj +++ b/Telegram.Net/Telegram.Net.csproj @@ -5,7 +5,7 @@ net7.0 enable enable - 1.0.0 + 1.0.1 yawaflua Telegram.Net Telegram.Bots extender pack, what provides to user attributes, which can used with services