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

Sha*_*iel 4 c# asp.net-core-mvc asp.net-core asp.net-core-webapi asp.net-core-2.0

在我的 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);
    //...
}
Run Code Online (Sandbox Code Playgroud)

在单例类中,我像这样包装这个 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()
    {
        //...
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果 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);
    });
}
Run Code Online (Sandbox Code Playgroud)

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

Bjo*_*eul 10

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

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;
}
Run Code Online (Sandbox Code Playgroud)

然后将您的包装类注册为单例

services.AddSingleton(sp => new AppSettingsWrapper(sp.GetService<IOptionsMonitor<AppSettings>>()));
Run Code Online (Sandbox Code Playgroud)


Sim*_*Ged 5

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

不幸的是,您无法将其加载IOptionsSnapshot到 Singleton 服务中。IOptionsSnapshot是 Scoped 服务,因此您只能在 Scoped 或 Transient 注册类中引用它。

但是,仔细想想,这是有道理的。设置更改时需要重新加载,因此如果将它们注入单例,则该类将永远不会获得更新的设置,因为不会再次为单例调用构造函数。

  • 如果当配置源(在本例中是文件)更改时 reloadOnChange 不 ping 更改句柄,那么 reloadOnChange 的目的是什么? (4认同)