在ASP.NET Core中使用reloadOnChange重新加载选项

时间:2018-06-29 08:28:51

标签: c# asp.net-core asp.net-core-mvc asp.net-core-2.0 asp.net-core-webapi

在我的ASP.NET Core应用程序中,我将appsettings.json绑定到一个强类型的类 AppSettings

public Startup(IHostingEnvironment environment)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(environment.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .AddJsonFile($"appsettings.{environment.EnvironmentName}.json", optional: true, reloadOnChange: true)
        .AddEnvironmentVariables();

    Configuration = builder.Build();
}

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<AppSettings>(Configuration);
    //...
}

在单例类中,我将这个AppSettings类包装为:

public class AppSettingsWrapper : IAppSettingsWrapper
{
    private readonly IOptions<AppSettings> _options;

    public AppSettingsAdapter(IOptions<AppSettings> options)
    {
        _options = options ?? throw new ArgumentNullException("Options cannot be null");
    }

    public SomeObject SomeConvenienceGetter()
    {
        //...
    }
}

现在,如果json文件发生更改,我正在努力重新加载AppSettings。我在某处读到,类 IOptionsMonitor 可以检测到更改,但不适用于我的情况。

出于测试目的,我尝试这样调用 OnChange 事件:

public void Configure(IApplicationBuilder applicationBuilder, IOptionsMonitor<AppSettings> optionsMonitor)
{
    applicationBuilder.UseStaticFiles();
    applicationBuilder.UseMvc();

    optionsMonitor.OnChange<AppSettings>(vals => 
    {
        System.Diagnostics.Debug.WriteLine(vals);
    });
}

当我更改json文件时,永远不会触发该事件。有人知道我可以更改些什么以使重装机制在我的方案中工作吗?

3 个答案:

答案 0 :(得分:4)

您需要注入IOptionsSnapshot<AppSettings>才能使重新加载正常工作。

很遗憾,您无法将IOptionsSnapshot加载到Singleton服务中。 IOptionsSnapshot是范围服务,因此您只能在范围或瞬态注册类中引用它。

但是,如果考虑一下,那是有道理的。更改设置时需要重新加载设置,因此,如果将它们注入到Singleton中,则该类将永远不会获得更新的设置,因为不会为Singleton再次调用构造函数。

答案 1 :(得分:2)

您可以做的是像在 AppSettingsWrapper 中一样在config类周围创建包装器类,然后注入IOptionsMonitor。然后保留您的设置类的私有属性。该包装器可以作为单例注入,并且IOptionsMonitor将跟踪您的更改。

react-dom

然后将包装器类注册为单例

public class AppSettingsWrapper
{
    private AppSettings _settings;

    public AppSettingsWrapper(IOptionsMonitor<AppSettings> settings)
    {
        _settings = settings.CurrentValue;

        // Hook in on the OnChange event of the monitor
        settings.OnChange(Listener);
    }

    private void Listener(AppSettings settings)
    {
        _settings = settings;
    }

    // Example getter
    public string ExampleOtherApiUrl => _settings.ExampleOtherApiUrl;
}

答案 2 :(得分:0)

如果您想拥有一个单例IHostedService,例如注册为单例,并且Execute方法被计时器重复触发+您希望每个触发器上有一个新的IOptionsSnapshot ,您可以使用以下代码:

public MyHostedService (IServiceProvider serviceProvider)
{
    _serviceProvider = serviceProvider;
}

private void ExecutedByTimer ()
{
    using var scope = _serviceProvider.CreateScope();
    var options = scope.ServiceProvider.GetRequiredService<IOptionsSnapshot<MyHostedServiceOptions>>().Value;
    // Voila, options is an up-to-date snapshot
}