dependency injection
ILogger issue
Microsoft.Extensions.Logging
.NET troubleshooting
logging error

Unable to resolve ILogger from Microsoft.Extensions.Logging

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

The “unable to resolve ILogger” error in .NET usually means the dependency injection container was asked for the wrong logging type. In the built-in logging system, the normal constructor dependency is ILogger<TCategoryName>, not the non-generic ILogger interface by itself.

Why Plain ILogger Often Fails

The logging system is category-based. When you request ILogger<Worker>, the container knows the category should be the fully qualified name of Worker.

csharp
1using Microsoft.Extensions.Logging;
2
3public class Worker
4{
5    private readonly ILogger<Worker> _logger;
6
7    public Worker(ILogger<Worker> logger)
8    {
9        _logger = logger;
10    }
11}

If you request plain ILogger, the container has no category type to infer automatically. That is why resolution often fails even though logging is otherwise configured correctly.

Prefer ILogger<T> in Application Services

If a service currently looks like this:

csharp
1using Microsoft.Extensions.Logging;
2
3public class Worker
4{
5    public Worker(ILogger logger)
6    {
7    }
8}

Change it to this:

csharp
1using Microsoft.Extensions.Logging;
2
3public class Worker
4{
5    private readonly ILogger<Worker> _logger;
6
7    public Worker(ILogger<Worker> logger)
8    {
9        _logger = logger;
10    }
11}

That is the standard pattern in ASP.NET Core, worker services, and console apps that use the default host and container.

Make Sure Logging Is Registered

Using the right constructor type is only part of the fix. Logging services must also be registered in the container.

When you use the generic host, this is usually done for you:

csharp
1using Microsoft.Extensions.DependencyInjection;
2using Microsoft.Extensions.Hosting;
3
4var builder = Host.CreateApplicationBuilder(args);
5builder.Services.AddTransient<Worker>();
6
7using var host = builder.Build();
8var worker = host.Services.GetRequiredService<Worker>();

If you build a ServiceCollection manually, you need to add logging yourself:

csharp
1using Microsoft.Extensions.DependencyInjection;
2using Microsoft.Extensions.Logging;
3
4var services = new ServiceCollection();
5
6services.AddLogging(logging =>
7{
8    logging.AddConsole();
9});
10
11services.AddTransient<Worker>();
12
13using var provider = services.BuildServiceProvider();
14var worker = provider.GetRequiredService<Worker>();

Without AddLogging, even ILogger<Worker> will not be available.

Use ILoggerFactory for Dynamic Categories

Sometimes you really do need a non-generic logger. In that case, inject ILoggerFactory and create the logger explicitly:

csharp
1using Microsoft.Extensions.Logging;
2
3public class DynamicWorker
4{
5    private readonly ILogger _logger;
6
7    public DynamicWorker(ILoggerFactory loggerFactory)
8    {
9        _logger = loggerFactory.CreateLogger("DynamicCategory");
10    }
11}

This is appropriate when the category is not naturally tied to a single class type. The important point is that you still let the framework create the logger, rather than asking DI to infer a category from plain ILogger.

Watch How the Object Is Created

Another common source of confusion is bypassing the container:

csharp
var worker = new Worker(null);

If the service is created manually with new, dependency injection does not participate. That means no logger gets supplied, regardless of how correctly the container was configured elsewhere.

When constructor injection is part of the design, the service should be resolved from DI:

csharp
var worker = provider.GetRequiredService<Worker>();

This sounds obvious, but it shows up often in test code, quick console prototypes, and old codebases gradually moving toward DI.

Provider Configuration Is Separate

Providers such as Console logging, Serilog, or Application Insights affect where logs go. They do not change the core DI rule about ILogger<T>.

In other words, the following are separate concerns:

  • can the container resolve a logger dependency
  • which provider writes the resulting log entries

Mixing those up leads people to blame the provider package when the actual issue is constructor type or missing AddLogging.

Common Pitfalls

  • Injecting plain ILogger instead of ILogger<T>.
  • Forgetting to call AddLogging when building a raw ServiceCollection.
  • Creating services manually with new and expecting dependency injection to fill constructor arguments.
  • Blaming the logging provider when the actual issue is DI registration or type choice.
  • Mixing multiple startup paths and only configuring logging in one of them.

Summary

  • In most .NET services, inject ILogger<T> rather than plain ILogger.
  • Ensure logging services are registered, especially in manually built containers.
  • Use ILoggerFactory when you need a non-generic logger with a dynamic category.
  • Resolve services from the DI container instead of constructing them manually.
  • Separate logger resolution issues from provider configuration issues when troubleshooting.

Course illustration
Course illustration

All Rights Reserved.