0

I'm writting my Telegram Bot with N-layer architecture. I asked question about an access to dispose context and got an answer here. I wrote HostedService class and MessageHandler, but I got a new error, which I couldn't resolve.

HostedService class:

public class TelegramHostedService : IHostedService
    {
        private IServiceScopeFactory _scopeFactory;
        private TelegramBotClient _client;
        private readonly string _token = "1973694233:AAHqgQSqs7lz-TE7n5HVCm5Z692ZRiivQcc";
        public TelegramHostedService(IServiceScopeFactory scopeFactory)
        {
            _scopeFactory = scopeFactory;
        }


        public Task StartAsync(CancellationToken cancellationToken)
        {
            _client = new TelegramBotClient(_token);
            _client.StartReceiving();
            _client.OnMessage += OnMessageHandlerAsync;

            return Task.CompletedTask;
        }

        private async void OnMessageHandlerAsync(object sender, MessageEventArgs e)
        {
            using var scope = _scopeFactory.CreateScope();
            var handler = scope.ServiceProvider.GetRequiredService<MessageHandler>();
            await handler.Handle(sender, e, _client);
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            throw new System.NotImplementedException();
        }
    }

MessageHandler class:

public class MessageHandler
    {
        private readonly ParserService _parser;
        public MessageHandler(ParserService parser)
        {
            _parser = parser;
        }
        public async Task Handle(object sender, MessageEventArgs e, ITelegramBotClient _client)
        {
            if (e.Message is not { Type: Telegram.Bot.Types.Enums.MessageType.Text } || string.IsNullOrEmpty(e.Message.Text)) return;

            try
            {
                if (e.Message.Text.ToLower().Contains("/lastnews"))
                {
                    await SendArticleAsync(e.Message.Chat.Id, 0, 5, _client);
                }

                if (e.Message.Text.ToLower().Contains("/load"))
                {
                    await OnLoadMoreNewsAsync(e.Message.Chat.Id, 0, 5, _client);
                }

                if (e.Message.Text.ToLower().Contains("/subscribe"))
                {
                    await OnStartSubscibeAsync(e.Message.From.Username, e.Message.From.Id);
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        private async Task SendArticleAsync(long chatId, int offset, int count, ITelegramBotClient _client)
        {
            var articles = await _parser.MakeHtmlRequest(offset, count);
            foreach (var article in articles)
            {
                var linkButton = KeyboardGoOver("Перейти", article.Href);
                await _client.SendPhotoAsync(chatId: chatId, photo: article.Image,
                    caption: $"*{article.Title}*", parseMode: Telegram.Bot.Types.Enums.ParseMode.Markdown, replyMarkup: linkButton);

            }
            await OnLoadMoreNewsAsync(chatId, offset + count, count, _client);
        }

        private static async Task OnLoadMoreNewsAsync(long chatId, int offset, int count, ITelegramBotClient _client)
        {
            var keyboard = new InlineKeyboardMarkup(new[]
            {
                new[]
                {
                    InlineKeyboardButton.WithCallbackData("Загрузить", $"load_{offset}_{count}")
                },

            });

            await _client.SendTextMessageAsync(chatId, "Хотите ли загрузить еще 5 новостей?", replyMarkup: keyboard);
        }

        private static async Task OnStartSubscibeAsync(string userName, long userId)
        {

        }

        private static InlineKeyboardMarkup KeyboardGoOver(string text, string url)
        {
            return new InlineKeyboardMarkup(new[]
            {
                new[]
                {
                    InlineKeyboardButton.WithUrl(text, url)
                },
            });
        }
    }

Startup Configure method:

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();

            services.AddDbContext<ApplicationContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("DefaultConnection"),
                    o => { o.CommandTimeout(100); }));
            BLLInjection.Injection(services);
            services.AddScoped<MessageHandler>();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "TelegramBot.WebApi", Version = "v1" });
            });
        }

BLL and DAL Injection you could see in my previous question.

When I send a request from Telegram, I get the following error:

System.AggregateException: 'Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: TelegramBot.WebApi.Handlers.MessageHandler Lifetime: Scoped ImplementationType: TelegramBot.WebApi.Handlers.MessageHandler': Unable to resolve service for type 'TelegramBot.BLL.Services.ParserService' while attempting to activate 'TelegramBot.WebApi.Handlers.MessageHandler'.)'

InvalidOperationException: Unable to resolve service for type 'TelegramBot.BLL.Services.ParserService' while attempting to activate 'TelegramBot.WebApi.Handlers.MessageHandler'.

Ilya
  • 5
  • 3
  • The error message is pretty explicit, you haven't told your app how to construct a `ParserService` object. You should do something like `services.AddScoped();` though that looks like a concrete object so you should consider making an interface and using that. – DavidG Oct 08 '21 at 09:43
  • Replace `services.AddTransient();` with `services.AddScoped();` and then inject `IParser` instead of `ParserService` inside `MessageHandler`'s constructor: `public MessageHandler(IParser parser)` - fixed. – Ermiya Eskandary Oct 08 '21 at 09:45
  • Looking at your previous question (that info should be in HERE not THERE) it seems you should change the `MessageHandler` to take the interface in it's constructor, e.g. `public MessageHandler(IParser parser)` – DavidG Oct 08 '21 at 09:46
  • 1
    @ErmiyaEskandary thank you very much! I had this issue, because when I tried using IParser, I used from AngleSharp library. Very stupid issue. Thanks. How could I do your comment like an answer? – Ilya Oct 08 '21 at 10:23

0 Answers0