Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/274.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在ASP.NET Core中使用reloadOnChange重新加载选项_C#_Asp.net Core_Asp.net Core Mvc_Asp.net Core 2.0_Asp.net Core Webapi - Fatal编程技术网

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

C# 在ASP.NET Core中使用reloadOnChange重新加载选项,c#,asp.net-core,asp.net-core-mvc,asp.net-core-2.0,asp.net-core-webapi,C#,Asp.net Core,Asp.net Core Mvc,Asp.net Core 2.0,Asp.net Core Webapi,在我的ASP.NET核心应用程序中,我将appsettings.json绑定到强类型类appsettings 公共启动(IHostingEnvironment环境) { var builder=new ConfigurationBuilder() .SetBasePath(environment.ContentRootPath) .AddJsonFile(“appsettings.json”,可选:true,重载更改:true) .AddJsonFile($“appsettings.{envir

在我的ASP.NET核心应用程序中,我将appsettings.json绑定到强类型类appsettings

公共启动(IHostingEnvironment环境)
{
var builder=new ConfigurationBuilder()
.SetBasePath(environment.ContentRootPath)
.AddJsonFile(“appsettings.json”,可选:true,重载更改:true)
.AddJsonFile($“appsettings.{environment.EnvironmentName}.json”),可选:true,重载更改:true)
.AddenEnvironmentVariables();
Configuration=builder.Build();
}
public void配置服务(IServiceCollection服务)
{
服务。配置(配置);
//...
}
在singleton类中,我将此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()
    {
        //...
    }
}
公共类appsetingswrapper:IAppSettingsWrapper
{
私有只读IOP选项;
公共应用程序设置适配器(IOOptions选项)
{
_选项=选项??抛出新的ArgumentNullException(“选项不能为null”);
}
公共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);
    });
}
public void配置(IAApplicationBuilder applicationBuilder、IOPTIONS监视器选项监视器)
{
applicationBuilder.UseStaticFiles();
applicationBuilder.UseMvc();
选项Monitor.OnChange(VAL=>
{
系统诊断调试写线(VAL);
});
}

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

您需要注入
IOptionsSnapshot
以使重新加载工作正常

很遗憾,您无法将
IOptionsSnapshot
加载到单例服务中
IOptionsSnapshot
是一个作用域服务,因此您只能在作用域或临时注册类中引用它


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

您可以做的是像在AppSettingsRapper中那样围绕配置类创建包装类并注入IOPTIONS监视器。然后保留设置类的私有属性。该包装器可以作为单例注入,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;
}
公共类应用程序设置说唱程序
{
私有应用程序设置(U设置);
公共应用程序设置rapper(IOPTIONS监视器设置)
{
_设置=设置.CurrentValue;
//钩住监视器的OnChange事件
settings.OnChange(监听器);
}
专用void侦听器(应用设置)
{
_设置=设置;
}
//示例吸气剂
公共字符串ExampleOtherApiUrl=>\u设置。ExampleOtherApiUrl;
}
然后将包装器类注册为singleton

services.AddSingleton(sp => new AppSettingsWrapper(sp.GetService<IOptionsMonitor<AppSettings>>()));
services.AddSingleton(sp=>newappsetingswrapper(sp.GetService());

如果您想要一个singleton
IHostedService
,例如注册为singleton,并且
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
}
公共MyHostedService(IServiceProvider服务提供商)
{
_服务提供者=服务提供者;
}
private void ExecutedByTimer()
{
使用var scope=_serviceProvider.CreateScope();
var options=scope.ServiceProvider.GetRequiredService().Value;
//瞧,选项是最新的快照
}

我想我可能可以在“OnChange”事件中将AppSettingsRapper与新的AppSettings重新绑定。不幸的是,我不得不更改包装类的生存期,因为除了罕见的重新加载之外,它从未更改。除非您有真正令人信服的理由将其保留为一个单独的类,例如实时性能,否则切换到
范围内的
服务应该不会给您带来太多的惩罚,毕竟,您仍然在注入同一个类,只是注册发生了更改。没有任何东西阻止您使用IServiceProvider.CreateScope在singleton中创建作用域。如果配置源(在本例中为文件)更改时,reloadOnChange没有ping更改句柄,那么reloadOnChange的目的是什么?这感觉像是一个bug。如果要添加json文件,并且希望对更改进行重新加载调用,则保存对该文件的更改时应调用任何更改处理程序,并将haschanged设置为true。
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
}