Add EvenLogging to an IHost container

102 views Asked by At

I’m creating a console app and have recently started adding custom services to the IHost container so I can simply pass the IHost to any number of factory classes and have everything thing I need to configure them. But I’ve gotten stuck when it comes to adding Windows Event Logging as a service, could use some help getting past this.

My Main static method in Program calls CreateHostBuilder and returns an IHostBuilder as shown below.

    public static IHostBuilder CreateHostBuilder(string[] args)
    {
        IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
        configurationBuilder.AddJsonFile("appsettings.json");
        IConfiguration configuration = configurationBuilder.Build();

        var hostBuilder = Host.CreateDefaultBuilder(args)
            .ConfigureLogging((hostContext, logging) =>
            {
                logging.ClearProviders();
                logging.SetMinimumLevel(LogLevel.Information);
                logging.AddEventLog(eventViewerSettings =>
                {
                    eventViewerSettings.SourceName = "MeCore2";
                    eventViewerSettings.LogName = "Application";
                    eventViewerSettings.MachineName = ".";
                });
            })
           .ConfigureServices(services => services.AddDbContext<MeCore2Context>())
            // Add custom service for performing DNS queries
            .ConfigureServices(services => services.AddTransient<IDnsQueryService>(DnsQueryFactory.Create))
            // Add custom service for Managing Runtime Environment Settings
            .ConfigureServices(services => services.AddTransient<IEnvironmentSettings>(EnvironmentSettingsFactory.Create))
            // Add custom service for Managing String Extractions
            .ConfigureServices(services => services.AddTransient<IExtractStringsService>(ExtraxtStringsFactory.Create))
            // Add custom service for IP GeoLocation
            .ConfigureServices(services => services.AddTransient<IIpGeolocationService>(IpGeolocationFactory.Create));

        return hostBuilder;
    }

My factory classes are implemented like this.

public static class DnsQueryFactory
{
    public static DnsQueryService Create(IServiceProvider serviceProvider)
    {
        bool exceptionDisplayOnly = serviceProvider.GetRequiredService<IEnvironmentSettings>().WriteErrorsToEventLogs;
        IHost host = serviceProvider.GetRequiredService<IHost>();

        return new DnsQueryService(exceptionDisplayOnly, host);
    }
}

And my concrete service constructors are implemented like this.

    public DnsQueryService(bool exceptionDisplayOnly, IHost host)
    {
        this.exceptionDisplayOnly = exceptionDisplayOnly;
        this.logger = host.Services.GetRequiredService<ILogger>();
        this.environmentSettings = host.Services.GetRequiredService<IEnvironmentSettings>();
    }

When I ran the app after setting up in this manner, I was unable to pull an ILogger from the host container, I could though, pull an ILoggerFactory then I needed to take some additional steps before I had a fully functional ILogger.

I would like to be able to pull the ILogger from the Host container with it fully configured and ready to use for exception handling, warnings, and basic information logging. But I'm stumped here as I can't seem to get the right syntax for using the ILoggingBuilder or ILoggerFactory into the Host container.

I started down the path of creating a static class EventLoggingServices that would accept an IServiceProvider finish out the configuration steps and return an ILogger, but this too has got me stumped. I'm close but not where I need to be and can't find a blog that covers this approach, either that or I'm going at this the wrong way, to begin with. Appreciate the help and thanks in advance.

I believe I've answered my own question with the following code, it is writing to the event logs. I implemented a factory method to encapsulate the ILogger<T> as follows.

public static class EventLoggingFactory
{
    public static ILogger<IEventLogging> Create(IServiceProvider serviceProvider)
    {
        return new EventLogging().EventLogger;
    }
}

public class EventLogging : IEventLogging
{
    #region *-- Private Members --*

    private ILogger<IEventLogging> _logger = null;

    #endregion

    public ILogger<IEventLogging> EventLogger { get { return this._logger; } }

    public EventLogging()
    {
        EventLogSettings settings = new EventLogSettings();
        settings.LogName = "Application";
        settings.SourceName = "MeCore2";
        settings.MachineName = ".";
        ILoggerFactory loggerFactory = new LoggerFactory();
        loggerFactory.AddProvider(new EventLogLoggerProvider(settings));
        this._logger = loggerFactory.CreateLogger<IEventLogging>();
    }
}

public interface IEventLogging
{
    ILogger<IEventLogging> EventLogger { get; }
}

And in my HostBuilder the following:

.ConfigureServices(services => services.AddTransient<ILogger>(EventLoggingFactory.Create))

What I haven't considered and I'm still wrapping my head around are service LifeTimes. Using this approach the Ilogger is Transient, but is that the best way to implement it?

1

There are 1 answers

0
DooHickey On

The final code block on this post has been a sufficient solution for my needs. With a little more effort I've been able to expand the features used to capture log data for viewing in Windows Event Viewer.