Unable to resolve ILogger from Microsoft.Extensions.Logging
ILogger
is no longer registered by default but ILogger<T>
is. If you still want to use ILogger you can register it manually with the following (in Startup.cs
):
public void ConfigureServices(IServiceCollection services)
{
var serviceProvider = services.BuildServiceProvider();
var logger = serviceProvider.GetService<ILogger<AnyClass>>();
services.AddSingleton(typeof(ILogger), logger);
...
}
Where AnyClass
can be something generic, such as:
public class ApplicationLogs
{
}
So:
public void ConfigureServices(IServiceCollection services)
{
var serviceProvider = services.BuildServiceProvider();
var logger = serviceProvider.GetService<ILogger<ApplicationLog>>();
services.AddSingleton(typeof(ILogger), logger);
...
}
ILogger
will now resolve via constructor injection.
In .NET Core, ILogger<T>
is automatically registered for you. As ILogger<T>
inherits from ILogger
, you can request an instance of ILogger<T>
from the IServiceProvider
.
For example:
services.AddSingleton<ILogger>(svc => svc.GetRequiredService<ILogger<MyClassType>>());
Note that this will return an ILogger<MyClassType>
wherever you've got a non-generic ILogger
constructor parameter so if you need more than one, look into creating it specifically for that instance by using the AddSingleton
(or transient/or scoped) implementationFactory override.
I am assuming you are using the default template for .net core web application.
In your your Startup.cs you should have a method like this↓↓↓↓↓↓↓
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
//Do the service register here and extra stuff you want
services.AddLogging(config =>
{
config.AddDebug();
config.AddConsole();
//etc
});
}
Edit: I have written a simple program for you to show how it works
public class MyClass
{
private readonly ILogger<MyClass> _logger;
public MyClass(ILogger<MyClass> logger)
{
_logger = logger;
}
public void MyFunc()
{
_logger.Log(LogLevel.Error, "My Message");
}
}
public class Program
{
public static void Main(string[] args)
{
var services = new ServiceCollection().AddLogging(logging => logging.AddConsole());
services.AddSingleton<MyClass>();//Singleton or transient?!
var s = services.BuildServiceProvider();
var myclass = s.GetService<MyClass>();
}
}
Edit: Output of the program:
As noted in a comment, the accepted answer has the problem that BuildServiceProvider
should not be used in ConfigureServices
, since it creates another copy of each singleton (in fact, of the whole DI container). Here is an alternative one-liner that avoids that problem. In ConfigureServices
, add the line
services.AddSingleton<Microsoft.Extensions.Logging.ILogger>(provider =>
provider.GetRequiredService<Microsoft.Extensions.Logging.ILogger<AnyClass>>());
where AnyClass
can be any class, as explained in the accepted answer. This redirects the resolution of ILogger
to that of ILogger<AnyClass>
.
Like the accepted answer, this one has the disadvantage that Serilog's SourceContext
will be set to AnyClass
. So, if your Serilog configuration contains an outputTemplate
that contains {SourceContext}
, your log will show AnyClass
instead of the class that contains the logging statement.