C# 在ASP.NET Core中使用reloadOnChange重新加载选项
在我的ASP.NET核心应用程序中,我将appsettings.json绑定到强类型类appsettingsC# 在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
公共启动(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());
如果您想要一个singletonIHostedService
,例如注册为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
}