5

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

1 Answers1

5

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>(); }
}
dadhi
  • 4,807
  • 19
  • 25
  • This looks pretty good but in fact I'm on a Xamarin.Forms Prism App and using the Interfaces of Microsoft.Extensions.Logging.Abstractions and DryIoc 2.12.6. On UWP I get an 'System.ArgumentNullException' without any conrete location. On Android I get an "System.InvalidOperationException: not a generic method definition" in App.xaml.cs:61. I could not test on iOS. I have created a simple sample at [github/dernippel/PrismNetCoreLoggingApp](https://github.com/dernippel/PrismNetCoreLoggingApp) for further investigation. – Alexander Sandiego Feb 22 '18 at 14:40
  • Check that `typeof(LoggerFactory).GetMethod("CreateLogger")` returns not null. – dadhi Feb 23 '18 at 10:10
  • I checked that. `typeof(LoggerFactory).GetMethod("CreateLogger")` is not null, it's `Microsoft.Extensions.Logging.ILogger CreateLogger(System.String)` on both platforms (UWP and Android). – Alexander Sandiego Feb 23 '18 at 12:59
  • There seems to be multiple Methods: 1. `CreateLogger(string categoryName):ILogger`, 2. `CreateLogger(this IloggerFactory factory):ILogger` and 3. `CreateLogger(this ILoggerFactory factory, Type type):ILogger`. I guess the 2nd one is the right one, but GetMethod returns the first one. – Alexander Sandiego Feb 23 '18 at 13:06
  • The problem is now that `CreateLogger`is a static extension method (`public static Microsoft.Extensions.Logging.ILogger CreateLogger(this Microsoft.Extensions.Logging.ILoggerFactory factory) Member of Microsoft.Extensions.Logging.LoggerFactoryExtensions`). I was able to get that method via `var loggerFactoryExtensionMethod = typeof(LoggerFactoryExtensions).GetMethod("CreateLogger",new Type[] { typeof(ILoggerFactory) });` but using it will cause a `DryIoc.ContainerException: Factory instance provided Microsoft.Extensions.Logging.LoggerFactory But factory method is static`. – Alexander Sandiego Feb 23 '18 at 15:57
  • I have added example with the static extension method – dadhi Feb 23 '18 at 19:31
  • There is another overload of `CreateLogger` in `LoggerFactoryExtensions` so i had to use `var loggerFactoryMethod = typeof(LoggerFactoryExtensions).GetMethod("CreateLogger", new Type[] { typeof(ILoggerFactory) });` for getting the correct one. With that change everything is working now. I will update my Sample-Repo too. Thanks! – Alexander Sandiego Feb 26 '18 at 08:15
  • Great, than accept my answer, so that others may quickly find a working solution. – dadhi Feb 26 '18 at 12:29