Reputation: 16186
I'd like to have my .Net Core 3.1 app automatically reload its configuration as the file changes on disk, but I'm having trouble getting this to work with the Options pattern. I run my app, save changes to the config file, and it's never called. Why doesn't the IOptionsMonitor instance ever call the OnChange handler? What am I missing?
Program.cs IHostBuilder creation
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(config => configuration = config.Build())
.ConfigureServices((hostContext, services) => {
var separateConfig = new ConfigurationBuilder()
.AddJsonFile("SeparateConfig.json", optional: false, reloadOnChange: true)
.Build();
services
.AddSingleton<MyMainService>()
.Configure<MySeparateConfig>(c => separateConfig.Bind(c));
})
Service that uses MySeparateConfig
public class MyMainService
{
public MyMainService(IOptionsMonitor<MySeparateConfig> config)
{
if (config is null) throw new ArgumentNullException(nameof(config));
ConfigChangeHandle = config.OnChange(UpdateConfiguration);
// Perform initial configuration using config.CurrentValue here
}
private IDisposable ConfigChangeHandle { get; set; }
private void UpdateConfiguration(MySeparateConfig config)
{
// Never called
}
}
Upvotes: 6
Views: 11218
Reputation: 26558
For the reload mechanism to work with IOptionsMonitor<TOptions>
, an IOptionsChangeTokenSource<TOptions>
needs to be registered in the services.
If you need an OptionsBuilder<TOptions>
, for example to add validation, this can be achieved with AddOptions
+ BindConfiguration
(from the Microsoft.Extensions.Options.ConfigurationExtensions NuGet package if you don't have a dependency in ASP.NET Core)
services.AddOptions<MyConfig>().BindConfiguration("").Validate(…)
Note that the BindConfiguration
extensions method automatically registers the IOptionsChangeTokenSource<TOptions>
which is the magic required for the reload mechanism to work.
Upvotes: 11
Reputation: 16186
As @Nkosi pointed out in comments, this line was the problem:
// Wrong
.Configure<MySeparateConfig>(c => separateConfig.Bind(c));
When I replaced it with the line below, everything started working right:
// Right
.Configure<MySeparateConfig>(separateConfig);
Upvotes: 15