Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Register ILoggerFactory in DryIoc container

Tags:

I want to use Microsoft.Extensions.Logging with a DryIoc container.

The default way is to register the factory as an instance, inject it and create a logger:

ILoggerFactory loggerFactory = new LoggerFactory().AddDebug();
container.RegisterInstance(loggerFactory);

// inject factory in constructor
public MyService(ILoggerFactory loggerFactory){
 this.logger = loggerFactory.CreateLogger<MyService>()

 this.logger.LogInformation("Logger created");
}

But I want a more ASP.NET Core like behavior, where the Logger is directly injected:

// inject logger in constructor
public MyService(ILogger<MyService> logger){
 this.logger = logger;

 this.logger.LogInformation("Logger created");
}

So I need to create an Instance of the ILoggerFactory due to some configuration, and the ILogger<> Interface must be registered in the container using the "CreateLogger" Method when requested.

I tried using registration with a factory method from https://bitbucket.org/dadhi/dryioc/wiki/SelectConstructorOrFactoryMethod without any success.

Ended up with something like this, but the generic in CreateLogger<> is missing:

container.Register(typeof(ILogger<>), made: Made.Of(() => loggerFactory.CreateLogger<>()));

Maybe anyone can help.

Edit

You have to do this for getting the correct factory method:

var loggerFactoryMethod = typeof(LoggerFactoryExtensions).GetMethod("CreateLogger", new Type[] { typeof(ILoggerFactory) });

I've created and updated a working sample of this using Xamarin.Forms (with Prism and DryIoc) at github.com/dernippel/PrismNetCoreLoggingApp

like image 591
Alexander Sandiego Avatar asked Feb 21 '18 17:02

Alexander Sandiego


1 Answers

Here is the full working example based on sample interfaces and classes.
Live code to play is here.

using System;
using DryIoc;

public class Program
{
    public static void Main()
    {   
        var container = new Container();

        // note usage of UseInstance instead of obsolete RegisterInstance
        container.UseInstance(new LoggerFactory()); 

        var loggerFactoryMethod = typeof(LoggerFactory).GetMethod("CreateLogger");

        container.Register(typeof(ILogger<>), made: Made.Of(
            req => loggerFactoryMethod.MakeGenericMethod(req.Parent.ImplementationType),
            ServiceInfo.Of<LoggerFactory>()));

        container.Register<MyService>();

        container.Resolve<MyService>();
    }

    class MyService 
    {   
        public MyService(ILogger<MyService> logger) { logger.Log("Hey!"); }
    }

    interface ILogger<T> 
    {
        void Log(string msg);
    }

    class ConsoleLogger<T> : ILogger<T>
    {
        public void Log(string msg) { Console.WriteLine(typeof(T) + ": " + msg); }
    }

    class LoggerFactory 
    {
        public ILogger<T> CreateLogger<T>() { return new ConsoleLogger<T>(); }
    }
}

Update for static LoggerFactoryExtensions

For the static method the setup is more simple, you don't need to specify a factory instance via ServiceInfo.Of<LoggerFactory>(), it will be injected as any other parameter.

Here is the changes (live sample is updated):

    var loggerFactoryMethod = typeof(LoggerFactoryExtensions).GetMethod("CreateLogger");

    container.Register(typeof(ILogger<>), made: Made.Of(
        req => loggerFactoryMethod.MakeGenericMethod(req.Parent.ImplementationType)));

Given the extensions:

public static class LoggerFactoryExtensions
{
    public static ILogger<T> CreateLogger<T>(this LoggerFactory f) { return new ConsoleLogger<T>(); }
}
like image 57
dadhi Avatar answered Sep 19 '22 13:09

dadhi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!