Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass dependencies to a custom .NET Core ILoggerProvider

I am creating a custom .NET Core ILoggerProvider that requires some dependencies to be passed into its constructor.

I believe I am using a fairly common pattern to initialize my logging implementation; it looks something like this:

var services = new ServiceCollection();

// Register some services here

services.AddLogging(builder =>
{
    builder.AddProvider(new DebugLoggerProvider());
});

var provider = services.BuildServiceProvider();

I want to add my new provider within the AddLogging block, in the same way that the DebugLoggerProvider is currently added.

My custom provider requires some other services to be passed into its constructor and since these are already registered with the ServiceCollection, I assume that I should be able to reference them. However, unlike methods such as AddSingleton, which have an overload that exposes the IServiceProvider, AddLogging doesn't seem to offer an equivalent.

Is there a simple way to achieve this, or am I attempting to do something that contradicts the way .NET Core logging was designed to be deployed?

UPDATE:

After experimenting with the suggestions proposed by @Nkosi, I can confirm that it is possible to get this to work by bypassing AddLogging and directly implementing what it does internally, as follows:

var services = new ServiceCollection();

// Register some services
services.AddSingleton<IMyService, MyService>();

// Initialize logging
services.AddOptions();
services.AddSingleton<ILoggerFactory, LoggerFactory>();
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
services.AddSingleton<ILoggerProvider>(p => new DebugLoggerProvider());
services.AddSingleton<ILoggerProvider>(p => new MyLoggerProvider("Constant value", p.GetService<IMyService>()));

var provider = services.BuildServiceProvider();
like image 934
Tim Coulter Avatar asked Jun 22 '18 15:06

Tim Coulter


Video Answer


1 Answers

Now I am not sure if an extension already exists to do this but I see potential here.

First this is how AddProvider is defined in the source code repo.

public static ILoggingBuilder AddProvider(this ILoggingBuilder builder, ILoggerProvider provider) {
    builder.Services.AddSingleton(provider);
    return builder;
}

You could build up on that by making your own generic version

public static class MyLoggingBuilderExtensions {
    public static ILoggingBuilder AddProvider<T>(this ILoggingBuilder builder)
        where T: class, ILoggerProvider{
        builder.Services.AddSingleton<ILoggerProvider, T>();
        return builder;
    }
}

which should allow the DI container to build up the object graph when resolved

services.AddLogging(builder =>
{
    builder.AddProvider<CustomLoggerProvider>();
});

And there is room to extend this functionality, like adding your own overload that exposes the IServiceProvider and passing that on to the AddSingleton within the extension.

public static ILoggingBuilder AddProvider<T>(this ILoggingBuilder builder, Func<IServiceProvider, T> factory)
    where T: class, ILoggerProvider {
    builder.Services.AddSingleton<ILoggerProvider, T>(factory);
    return builder;
}

And used

services.AddLogging(builder => {
    builder.AddProvider<CustomLoggerProvider>(p => new CustomLoggerProvider("Constant value", p.GetService<IMyService>()));
});
like image 117
Nkosi Avatar answered Oct 18 '22 01:10

Nkosi