Search code examples
c#exceptionloggingconsole-applicationihostedservice

No exceptions or logging when missing dependency with IHostedService?


A colleague of mine is working on a console app, and we had a bit of a stumble. Launching the app would simply flash up an empty console window, which would then immediately close.

No breakpoints would be hit. No errors would be logged anywhere. No output.

After a few minutes of nosing around, I found the reason his app wasn't working was due to a dependency of his primary IHostedService not being registered. Simple enough to fix.

What I want to know is; why was there no exception or error logged to the console? This would have made our lives a lot easier.

Example (knocked together very rapidly):

//[Program.cs]

namespace FooNamespace
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var hostBuilder = Host.CreateDefaultBuilder(args)
                .UseConsoleLifetime()
                 .ConfigureServices((_, services) =>
                 {
                     services.AddHostedService<FooHostedService>();
 
                     //Missing dependency
                     //services.AddSingleton<IFooDependency, FooDependency>();
                 });
 
            hostBuilder.RunConsoleAsync();
        }
    }
}

// [FooHostedService.cs]

namespace FooNamespace
{
    internal class FooHostedService : IHostedService
    {
        private IFooDependency FooDependency { get; }
 
        public FooHostedService(IFooDependency fooDependency)
        {
            FooDependency = fooDependency;
        }
 
        public Task StartAsync(CancellationToken cancellationToken)
        {
            //If the program were working, this should display a string and pause for input
            Console.WriteLine("Hello, world!");
            Console.ReadKey(true);
            return Task.CompletedTask;
        }
 
        public Task StopAsync(CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }
    }
}

Solution

  • First of all, you are missing to await the RunConsoleAsync method. And that should be enough.

    Furthermore, I suggest you to use a logging library as Serilog (Serilog.AspNetCore): https://github.com/serilog/serilog/wiki/Configuration-Basics

    This is an example:

    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using Serilog;
    
    namespace FooNamespace
    {
        internal class Program
        {
            static async Task Main(string[] args)
            {
                Log.Logger = new LoggerConfiguration()
                    .WriteTo.Console()
                    .CreateBootstrapLogger();
    
                try
                {
                    var hostBuilder = Host.CreateDefaultBuilder(args)
                        .UseConsoleLifetime()
                         .ConfigureServices((_, services) =>
                         {
                             services.AddHostedService<FooHostedService>();
    
                             //Missing dependency
                             //services.AddSingleton<IFooDependency, FooDependency>();
                         });
    
                    await hostBuilder.RunConsoleAsync();
                }
                catch (Exception ex)
                {
                    Log.Fatal(ex, ex.Message);
                }
                finally
                {
                    Log.CloseAndFlush();
                }
            }
        }
    }
    

    In this case you would also log other types of problems, such as host building issues. See: https://nblumhardt.com/2020/10/bootstrap-logger/