Reputation: 20709
I want to start logging before webhost, so startup errors are logged. So I followed Serilog's recommended init order: 1) configuration, 2) logging, 3) webhost. I'm not using CreateDefaultBuilder()
.
So my Program.cs
has:
// setup config
var envName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production";
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional:false, reloadOnChange:true)
.AddJsonFile($"appsettings.{envName}.json", optional:true, reloadOnChange:true)
.AddEnvironmentVariables()
.AddCommandLine(args)
.Build();
// setup Serilog logging
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration) // <<< uses config from above
.CreateLogger()
// setup webhost
new WebHostBuilder()
.UseConfiguration(configuration) // <<< uses config from above
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseSerilog()
.Build()
.Run();
This works, but changes in appsettings.json
are not detected even though I specified reloadOnChange:true
.
However when I use ConfigureAppConfiguration()
then changes are detected:
new WebHostBuilder()
.ConfigureAppConfiguration((context, config) => {
// .. duplicate config here
})
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseSerilog()
.Build()
.Run();
But that means duplication and possibly unforseen problems - i.e. this is a hack. How do I solve this?
UPDATE
As per @StephenZeng's answer, UseConfiguration
won't help me here, so I suppose I need to use ConfigureAppConfiguration
. But the problem remains - how do I init my config first, then use it multiple times without redefining it?
Upvotes: 1
Views: 2190
Reputation: 20709
The solution is to avoid UseConfiguration
and use ConfigureAppConfiguration
instead:
// setup config
// ..as before
// ..this is done only once
// setup Serilog logging
// ...as before
// setup webhost
new WebHostBuilder()
.ConfigureAppConfiguration((context, config) => {
config.AddConfiguration(configuration); // <<< uses config from above
})
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseSerilog()
.Build()
.Run();
Upvotes: 0
Reputation: 1193
I've run into the same issue, and I created a method with the responsibility to configure the builder. I then call the method from both Main
and when I build the web host. Something like this:
public static class Program
{
public static int Main()
{
var configuration = new ConfigurationBuilder()
.AddConfiguration()
.Build();
// setup Serilog logging
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
// Code removed for brevity...
}
private static IWebHost BuildWebHost() =>
WebHost.CreateDefaultBuilder()
.UseSerilog()
.UseStartup<Startup>()
.ConfigureAppConfiguration((hostingContext, config) =>
{
// Clear default configuration
config.Sources.Clear();
// Replace with our own configuration
config.AddConfiguration();
})
.Build();
private static IConfigurationBuilder AddConfiguration(this IConfigurationBuilder self) =>
self
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional:false, reloadOnChange:true)
.AddJsonFile($"appsettings.{envName}.json", optional:true, reloadOnChange:true)
.AddEnvironmentVariables();
}
Upvotes: 1
Reputation: 2818
From the document it is by design:
"UseConfiguration only copies keys from the provided IConfiguration to the host builder configuration. Therefore, setting reloadOnChange: true for JSON, INI, and XML settings files has no effect."
Upvotes: 3