With ASP.NET Core 3.0, the ability to inject an ILogger or ILoggerFactory into the Startup class has been removed, so we can no longer do this:
public class Startup | |
{ | |
public Startup(IConfiguration configuration, ILoggerFactory logFactory) | |
{ | |
Logger = logFactory.CreateLogger<Startup>(); | |
} | |
private ILogger Logger { get; } | |
public void ConfigureServices(IServiceCollection services) | |
{ | |
Logger.LogInformation("Registering Services"); | |
// And the rest | |
} | |
} |
I understand why this has been done, because creating a temporary DI container just for the startup process adds a lot of complexity and potential for errors.
However, my ConfigureServices
method (and the new ConfigureContainer
method added in 3.0) does quite a bit of work, including loading extension assemblies; I want to be able to log during that time.
I also want to make sure I only pass around the ILogger
from the Microsoft.Extensions.Logging
namespace to other objects used at startup.
The Workaround
I use NLog for my logging (https://nlog-project.org/). In my Program’s Main
method I configure it like so:
public static void Main(string[] args) | |
{ | |
// NLog: setup the nlog config first; this will configure all subsequent nlog factories | |
// with our nlog config. | |
NLogBuilder.ConfigureNLog("nlog.config"); | |
var host = Host.CreateDefaultBuilder(args) | |
.ConfigureWebHostDefaults(webHostBuilder => | |
{ | |
webHostBuilder | |
.UseContentRoot(Directory.GetCurrentDirectory()) | |
.UseStartup<Startup>(); | |
}) | |
.ConfigureLogging(logging => | |
{ | |
logging.ClearProviders(); | |
logging.SetMinimumLevel(LogLevel.Trace); | |
}) | |
// Use NLog to provide ILogger instances. | |
.UseNLog() | |
.Build(); | |
host.Run(); | |
} |
You can grab details on how to create an nlog.config file from the NLog docs, I won’t go into it here.
Then, in my Startup class, I can create the NLogLoggerProvider
class (this is sort of a factory for creating the Microsoft ILogger instances), and from that I can get my logger instance:
public class Startup | |
{ | |
public Startup(IConfiguration configuration) | |
{ | |
// Get the factory for ILogger instances. | |
var nlogLoggerProvider = new NLogLoggerProvider(); | |
// Create an ILogger. | |
Logger = nlogLoggerProvider.CreateLogger(typeof(Startup).FullName); | |
} | |
public void ConfigureServices(IServiceCollection services) | |
{ | |
Logger.LogInformation("Registering Services"); | |
// And the rest | |
} | |
} |
Hey presto, logging in the Startup class. Note that we are obviously outside the entire DI system for this logging (which is sort of the point).