'How to call a method on application crash before objects in DI container are disposed? c#

I have a console application that is running in Kubernetes. I want it to send an event through rabbit when it crashes on unhandled exception.

Here is simplified version of code:

namespace Arbitrage.DustCleaner
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddRabbit();
                    services.AddHostedService<DustCleanerService>();
                    services.AddServiceFaultHandler("peanut-arbitrage-dust-cleaner");
                });
    }
}



namespace Arbitrage.DustCleaner
{
    public class DustCleanerService : BackgroundService
    {
        private readonly IDustCleaner _dustCleaner;
        private readonly ServiceFaultHandler _faultHandler;

        private readonly int _waitingTimeMilliseconds;
        
        public DustCleanerService(
            ICommandLineOptions<DustCleanerOptions> options,
            IDustCleaner dustCleaner,
            ServiceFaultHandler faultHandler)
        {
            _dustCleaner = dustCleaner;
            _faultHandler = faultHandler;

            var dustCleanerOptions = options.Value;
            _waitingTimeMilliseconds = dustCleanerOptions.DustingIntervalInHours * 60 * 60 * 1000;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            _faultHandler.SetupFaultHandling();
            
            while (!stoppingToken.IsCancellationRequested)
            {
                await _dustCleaner.ExecuteAsync();

                await Task.Delay(_waitingTimeMilliseconds, stoppingToken);
            }
        }
    }
}



namespace Arbitrage.DustCleaner.Domain.Services
{
    public class ServiceFaultHandler
    {
        private readonly IBus _bus;
        
        private readonly string _serviceName;

        public ServiceFaultHandler(IBus bus, string serviceName)
        {
            _bus = bus;
            _serviceName = serviceName;
        }

        public void SetupFaultHandling()
        {
            AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
        }

        private async void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            if (!e.IsTerminating)
                return;
            
            var failedEvent = new ServiceFailedEvent
            {
                FailInfo = e.ExceptionObject.ToString(),
                ServiceName = _serviceName
            };
            // _bus here is already disposes
            await _bus.PublishAsync(failedEvent);
        }
    }
}



namespace Arbitrage.DustCleaner.Domain.Services
{
    public class CexDustCleaner : IDustCleaner
    {
        public async Task ExecuteAsync()
        {
            throw new Exception("Some stupid error");
        }
    }
}



The problem is that when CurrentDomainOnUnhandledException is called _bus object has already beed disposed, so I can't send a message. Solution with try/catch in ExecuteAsync won't work because some other services contains legacy code



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source