54

I have a ASP.NET MVC 6 (beta-4) app.

public void ConfigureServices(IServiceCollection services)
{
    // Logging
    services.AddLogging();

    // ...
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory)
{
    // Add the console logger.
    loggerfactory.AddConsole(minLevel: LogLevel.Warning);

    // ...
}

And I have a controller...

public class HomeController : 
    Controller
{
    ILogger _logger;

    public HomeController(ILogger logger) 
    {
        _logger = logger;
    }

    // ...
}

But when I'm not getting the service registered correctly somehow: InvalidOperationException: Unable to resolve service for type 'Microsoft.Framework.Logging.ILogger' while attempting to activate 'HomeController'.. What am I doing wrong with the registering the logger?

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
Travis
  • 10,444
  • 2
  • 28
  • 48
  • You didn't register `ILogger`. – Steven May 12 '15 at 15:20
  • Isn't that was `service.AddLogging()` does? I might have made a grand assumption with that, time to go source diving. – Travis May 12 '15 at 17:13
  • So, `AddLogging()` should register `ILogger<>`. Maybe I need to inject `ILogger` instead of `ILogger`. – Travis May 12 '15 at 17:18
  • Just looked in the vNext source code myself and I think you are right. But still, I wouldn't want to depend on a framework defined abstraction at all. For more infor, see [this](https://stackoverflow.com/questions/5646820/logger-wrapper-best-practice). – Steven May 12 '15 at 17:22
  • Oh, I thought I pasted the code link in: https://github.com/aspnet/Logging/blob/d874c5726e713d3eb34938f85faf7be61aae0f2a/src/Microsoft.Framework.Logging/LoggingServiceCollectionExtensions.cs . Microsoft is providing an abstraction so you can use any logger with just some configuration. I'm okay with that rather than sticking with a single one. Though I have never bothered to change a logger once it was on board. – Travis May 12 '15 at 17:24
  • Changing the underlying logging framework isn't your only concern. It's about defining an abstraction specific to your application needs, preventing your code from having an unneeded dependency on external code, and keeping code as testable as possible. – Steven May 12 '15 at 17:26
  • It's unclear to me how using this abstraction violates any of that. The abstraction is similar to other abstractions I've worked on, e.g. https://github.com/MassTransit/MassTransit/tree/develop/src/MassTransit/Logging – Travis May 12 '15 at 17:30
  • If you read [this](https://stackoverflow.com/a/5646876/264697), you'll understand that it violates both the ISP and DIP. – Steven May 12 '15 at 17:32
  • One other thing, since you are injecting a logger in your `HomtController`, make sure that [you aren't logging too much](https://stackoverflow.com/a/9915056/264697). – Steven May 12 '15 at 17:34

4 Answers4

104

I assumed that services.AddLogging(); was doing the right thing and registering ILogger. After looking at the source (https://github.com/aspnet/Logging/blob/d874c5726e713d3eb34938f85faf7be61aae0f2a/src/Microsoft.Framework.Logging/LoggingServiceCollectionExtensions.cs) I found that it's actually registering ILogger<>. Changing the signature of ILogger to ILogger<HomeController> makes the above example work.

public class HomeController : 
    Controller
{
    ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger) 
    {
        _logger = logger;
    }

    // ...
}

Thanks to @Steve for setting me on the right track to find this.

Travis
  • 10,444
  • 2
  • 28
  • 48
  • This works. I read they are going to alter RC2 to have return whatever T is (like ) so you can actually get your implementation and not just the interface methods. Currently, you can put anything in there and it works, looks like it ignores it. I tested ILogger just to test that theory and it worked. – b.pell Feb 12 '16 at 18:10
  • 1
    What T is actually used for, is the logging context. - you call ILogger where T would usually be the calling type., but could anything really. – VisualBean Mar 22 '16 at 14:52
  • You can also specify ILoggerFactory as described here https://docs.asp.net/en/latest/fundamentals/logging.html – stankovski Jun 21 '16 at 23:52
  • Really the signature was the issue. This have been working for me. ILogger. Thanks a lot. – Sandro Stadler Jun 29 '17 at 12:40
13

The services.AddLogging(); didn't worked for me, so I added these two statements to ConfigureServices:

services.AddSingleton<ILoggerFactory, LoggerFactory>();
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));

Now the DI container is happy and everything works.

rubito
  • 471
  • 6
  • 5
2

You can add the following line into your ConfigureServices() method:

services.AddTransient<ILogger>(s => s.GetService<ILogger<Program>>());
ADM-IT
  • 3,719
  • 1
  • 25
  • 26
0

.NET 5.0 Solution; its worked with normal controller and generic controller too:

public class EnhancedGeneric<T> : BaseApiController
{
    private readonly ILogger _logger;

    public EnhancedGeneric(ILoggerFactory logger)
    {
        _logger = logger.CreateLogger(typeof(T).Name);
    }

    public void OnGet()
    {
        _logger.LogInformation("GET pages called.");
    }
}
mRizvandi
  • 983
  • 1
  • 8
  • 20