Why does .NET Core DI container not inject ILogger?

In order for MS.DI to be able to do a mapping from ILogger to ILogger<T> where the T becomes the consumer, it must support context-based injection. This means that when building an application using MS.DI, you will have to let your classes depend on ILogger<T>.

There are multiple reasons why MS.DI lacks this feature. I think the two most important reasons are:

  • MS.DI only implements features that are required for framework components itself. Remember: MS.DI was built and designed especially for the ASP.NET Core framework, its components, and its third-parties. Much less to be a fully fledged DI Container
  • MS.DI tries to be a lowest common denominator (LCD) where it tries to only support features that all other DI Containers support as well to allow you to replace this built-in container with a more mature, feature-rich DI Container.

I understand your annoyance. It would be great to see MS.DI support context-based injection, because it makes a lot of sense to depend on ILogger instead for your application components, because this makes your code simpler, easier to test, and less error prone.

Unfortunately, because of MS.DI's design and its LCD philosophy, it's unlikely that it ever gets such feature. Every time Microsoft adds behavior, a long and complex discussion is started with maintainers of most DI Containers to see how such feature can be supported in a way that is compatible with all other libraries (I've been parted of many of these discussions myself). This is a daunting task, and already proved to be impossible in some cases.

Instead, it makes sense to select a more mature and feature-rich DI Container that contains such feature, and many other features. For Simple Injector, for instance, we added integration for injecting ILogger. But there are other DI Containers that allow you to inject ILogger.

The dependency injection system doesn't register ILogger. Instead it registers ILogger<T>. If you need an instance of a logger, you will need to accept ILogger<MyService>.

The reason behind this is that the generic argument is used to build the logger's category name--something which all loggers require. With a non-generic logger there's not necessarily a good default name. If you really want a non-generic ILogger, you can register one like this (change the name as you please):

services.AddSingleton(sp => sp.GetRequiredService<ILoggerFactory>().CreateLogger("DefaultLogger"));

Alternatively, you can accept an ILoggerFactory in your constructor and then create your own logger on the fly.