Search code examples
c#apidependency-injectionconsole-applicationservice-provider

Call a C# web API service in a console application


In one solution I have a .net 5 ASP.NET Core Web API, which contains an interface IEmailSender and the respective EmailSender implementation, and a console app project. In the console app I have created a derived scheduled service, where in a catch block I want to use an EmailSender to send an email with details of an error thrown in the system.

public StockOpeningValuesUpdateScheduledService(IScheduleConfig<StockOpeningValuesUpdateScheduledService> config, IHttpClientFactory factory, IServiceProvider serviceProvider)
            : base(config.CronExpression, config.TimeZoneInfo, serviceProvider)
        {
            _factory = factory;
            _serviceProvider = serviceProvider;
        }

        public override async Task DoWork(CancellationToken cancellationToken = default)
        {
            try
            {
                var client = _factory.CreateClient("trading");

                await client.PostAsync("company-buyable-shares/update-opening-values", null, cancellationToken);
            }
            catch (Exception ex)
            {
                using var serviceScope = _serviceProvider.CreateScope();

                var emailSender = serviceScope.ServiceProvider.GetRequiredService<IEmailSender>();

                await emailSender.SendAbnormalEventEmailAsync(ex);
            }
        }

I call the scheduled service in Program.cs of the console app, and try to register the EmailSender as a scoped service.

public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .ConfigureServices((_, services) =>
            {
                services.AddHttpClient("trading", client =>
                    client.BaseAddress = new Uri("https://localhost:44395"));

                services.AddScoped<IEmailSender, EmailSender>()
                .AddScheduledService<StockOpeningValuesUpdateScheduledService>(service =>
                {
                    service.CronExpression = "*/2 * * * *";
                    service.TimeZoneInfo = TimeZoneInfo.Utc;
                });            
            });

When I simulate an error in the console app (in order to receive an email about it) I get an exception

System.InvalidOperationException: 'Unable to resolve service for type 'StockTradingSimulator.BusinessLayer.Services.IEmailService' while attempting to activate 'StockTradingSimulator.BusinessLayer.Helpers.EmailSender'.

In the web API I have a setup as in my catch block above for another derived scheduled service which calls a scoped service method. This functionality is working, maybe because the scheduled service, and the scoped service and its interface are in the same project.

Does somebody have an idea how I can register and call successfully the EmailSender in my console app?

Thank you.


Solution

  • The problem is that EmailSender has unresolved dependencies. The dependency that is not resolved is IEmailService

    The code and description you posted has no reference about the interface which is causing the error. Where is the implementation for IEmailService?

    When you build the IServiceProvider, you need to have something that adds IEmailService to the DI container. Something like:

    services.AddScoped<IEmailService, MyEmailService>();