ASP.NET Core 中动态写入配置文件
由于上了K8S集群化管理,配置自然要从远程读取,使用配置中心后,应用程序打包成Docker Image时只有一个appsettings.json,程序启动时在Startup.cs中从远程加载配置后创建本地的appsettings.{ASPNETCORE_ENVIRONMENT}.json。大概代码如下:
public void ConfigureServices(IServiceCollection services)
{
//加载appsettings.json中的ACM配置
services.Configure<AliyunConfig>(Configuration.GetSection("AliyunACM"));
//封装好的从远程加载配置的方法,读取到远程配置后则会创建出appsettings.{ASPNETCORE_ENVIRONMENT}.json文件
services.AddAliyunACM();
}
加载配置中心的代码会放在读取其它配置之前,这样读取其它配置时就应该是远程的配置项。但是实际运行时却无法读取到变更后的配置项,Debug时却能正确读取,样例代码如下:
public void ConfigureServices(IServiceCollection services)
{
//加载appsettings.json中的ACM配置
services.Configure<AliyunConfig>(Configuration.GetSection("AliyunACM"));
//封装好的从远程加载配置的方法,读取到远程配置后则会创建出appsettings.{ASPNETCORE_ENVIRONMENT}.json文件
services.AddAliyunACM();
//此时读取出的值时空的。但是当你调试断点打在这里时,则能正确读取出配置项
var testConfig = configuration.GetValue<string>("TestConfig");
if(string.IsNullOrEmpty(testConfig))
{
throw new ArgumentNullException(nameof(testConfig));
}
}
查了很多资料无果后,自己撸了Configuration源码,发现原来当配置文件变更后IConfigurationRoot并不会立即重新读取,而是会有一个250毫秒的的延时,这个延时的作用是防止文件在未写入完成配置就重新加载(查看详情)。
知道原因后解决方案简单很多了,IConfigurationRoot接口具有Reload()方法,在写入文件后直接调用改方法即可:
public Startup(IConfiguration configuration)
{
ConfigurationRoot = configuration as IConfigurationRoot;
}
//public IConfiguration Configuration { get; }
public IConfigurationRoot ConfigurationRoot { get; }
public void ConfigureServices(IServiceCollection services)
{
//加载appsettings.json中的ACM配置
services.Configure<AliyunConfig>(Configuration.GetSection("AliyunACM"));
//封装好的从远程加载配置的方法,读取到远程配置后则会创建出appsettings.{ASPNETCORE_ENVIRONMENT}.json文件
services.AddAliyunACM();
//重新加载ConfigurationRoot
ConfigurationRoot.Reload();
//这时则能正确读取出配置项
var testConfig = configuration.GetValue<string>("TestConfig");
System.Console.WriteLine(testConfig);
}