4

I am working on an ASP.NET MVC application.

I have initialized my LoggerFactory in a static class which is called from Global.asax

using Microsoft.Extensions.Logging;
using Serilog;
using System.IO;

namespace web
{
    public static class LogConfig
    {
        public static LoggerFactory LoggerFactory = new LoggerFactory();

        public static void RegisterLogger()
        {
            LoggerFactory = new LoggerFactory();
            Log.Logger = new LoggerConfiguration().MinimumLevel.Debug().WriteTo.RollingFile(Path.Combine("", "log-{Date}.txt")).CreateLogger();
            LoggerFactory.AddSerilog();
        }
    }
}

now I want to use ninject, to inject an instance of ILogger into my constructor...

In my constructor I have:

private ILogger<MyTypeController> _logger;

public MyTypeController(ILogger<MyTypeController>) 
{
    // This works fine but I want to inject it
    _logger = LogConfig.LoggerFactory.CreateLogger<MyTypeController>();
}

The above code works, but I want to inject it using ninject... this is what I have tried but does not even compile:

kernel.Bind(typeof(ILogger<>)).ToProvider(LogConfig.LoggerFactory.CreateLogger<>());
Hooman Bahreini
  • 14,480
  • 11
  • 70
  • 137
  • 1
    Cross posted here: https://github.com/ninject/Ninject/issues/259 – BatteryBackupUnit Oct 20 '17 at 06:03
  • 4
    I would change the question and ask how to inject a logger created as `CreateLogger` into a constructor argument of non-generic interface `ILogger` instead of `ILogger`. Injection of a `ILogger` is just noise to the consumer that can lead to accidental errors when a wrong `T` is specified and it complicates testing. – Steven Oct 20 '17 at 08:17
  • Thanks @Steven... I can update the question. Basically I am trying to replicate what happens in MVC Core, in my MVC framework website. In MVC Core, ILoggerFactory and ILogger are both injected into the programme... but here I need to specifically call the create method of LoggerFactory... – Hooman Bahreini Oct 20 '17 at 08:23
  • 3
    Injecting `ILoggerFactory` and `ILogger` is a terrible idea, and as I see it, the only reason Microsoft is doing this (and promoting it publicly) is because their built-in container lacks the possibility to map a non-generic interface to a generic implementation. In other words they push bad practices because of their own lacking implementation. – Steven Oct 20 '17 at 08:26
  • Thanks again @Steven... So what should I do? I basically don't need the logger Factory, I am using Serilog, I just want to initialize Serilog once, in app start and inject it into classes for logging. I thought using LoggerFactory is a goodIdea, becasue I can change the providers... but I am really new to this... I would really appreciate if you give me a little more detail what would be the best approach? I am totally happy to change the approach. – Hooman Bahreini Oct 20 '17 at 08:33
  • 1
    I don't have the answer to your question; I'm not that experienced with Ninject. There will be others that will be able to help you with that. I can just help with asking the right question :) – Steven Oct 20 '17 at 08:35
  • First, correct your sample that you claim works. You are not even specifying a parameter name. Second, add the compilation exception that is keeping it from compiling: do not just make reference to it and not provide it. – Brett Caswell Nov 05 '17 at 06:24
  • @Brett, Create Logger has several overrides, this is correct usage: ILogger foo = factory.CreateLogger(); If you read my last comment, I said the code for the last example does not even compile, so I am asking for the correct syntax - there is no exception. – Hooman Bahreini Nov 05 '17 at 07:09

2 Answers2

9

I'm doing the following with NLog but it is also likely to work with Ninject:

var createLoggerMethod =
    typeof(LoggerFactoryExtensions).GetMethod(nameof(LoggerFactoryExtensions.CreateLogger),
        new[] {typeof(ILoggerFactory)});
kernel.Bind(typeof(ILogger<>)).ToMethod(context =>
{
    var createLoggerGeneric = createLoggerMethod.MakeGenericMethod(context.GenericArguments);
    var logger = createLoggerGeneric.Invoke(null, new []{ loggerFactory });
    return logger;
});
oeaoaueaa
  • 91
  • 1
  • 4
0

Reading the comments given by @Steven and also reading his blog on Simple Injector, I have realized that injecting a generic logger ILogger<T> is not really a good approach.

See this answer for more details.

Hooman Bahreini
  • 14,480
  • 11
  • 70
  • 137