ASP.NET Core 网站运行时修改设置如何自动生效 | 您所在的位置:网站首页 › vmware必须重新启动才能使配置生效 › ASP.NET Core 网站运行时修改设置如何自动生效 |
点击蓝字 关注我 在ASP.NET Core中,如果修改了appsettings.json中的设置,那么默认情况下就得重启网站才能生效。有没有办法在修改设置后自动刷新并应用呢? 背景 首先,我们看看默认模板建出来的 ASP.NET Core 网站,配置文件有两个: appsettings.json appsettings.Development.json 前者用于生产环境,后者用于开发环境,在Debug模式下,会优先使用 appsettings.Development.json 的设置。 在不显示指定的情况下,Program.cs 中的CreateWebHostBuilder() 方法会读取这两个设置文件。为了便于维护,大家通常会创建一个对应的class,用来强类型匹配设置项。比如这样: services.Configure(Configuration.GetSection(nameof(AppSettings))); 使用的时候用IOptions接口注入: public Ctor(IOptions settings) 如果你还不了解这种方法,可以参见我之前写的文章:https://edi.wang/post/2016/10/9/read-appsettings-aspnet-core (微信可能屏蔽了我的域名,复制到浏览器能打开) 问题 这种方法确实可以读取配置文件,并使用强类型约束和使用。但个缺点就是在网站运行时,如果修改了 appsettings.json 中的配置项,是不会当场生效的,必须重启网站才能应用。 比如我博客的网页标题,是来源于配置文件里的 SiteTitle,如果我在网站运行时登录服务器后台,改成 "Edi.Wang Test",是不会生效的,必须得等下次网站重启。 解决办法 还是刚才我博客的例子,我给标题赋值用的方法是在Razor页面里注入IOptions接口: @inject IOptions Settings 然后赋值: @Settings.Value.SiteTitle 解决办法非常简单,换个接口,用IOptionsSnapshot就行啦,在C#类的构造函数里注入的话也是一样的改法: @inject IOptionsSnapshot Settings 对比一下这两个接口: IOptions // Summary: // Used to retrieve configured TOptions instances. // // Type parameters: // TOptions: // The type of options being requested. public interface IOptions where TOptions : class, new() IOptionsSnapshot // Summary: // Used to access the value of TOptions for the lifetime of a request. // // Type parameters: // TOptions: public interface IOptionsSnapshot : IOptions where TOptions : class, new() 会发现 IOptionsSnapshot 会针对每个单独的请求去重新读取一次配置,而 IOptions 则是第一次读取完以后就将对象保存在内存里了。 听说你想这样做? 网上搜索到的方法通常让你这样做:修改Program.cs,在CreateWebHostBuilder() 方法里加入这么一段: ... WebHost.CreateDefaultBuilder(args) .ConfigureAppConfiguration((hostingContext, config) => { config.SetBasePath(Directory.GetCurrentDirectory()); config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); config.AddJsonFile("appsettings.Development.json", optional: false, reloadOnChange: true); config.AddEnvironmentVariables(); }) ... 这段代码的作用是,让我们自己指定应用启动时加载哪些配置源,在这个案例里,我们依旧加载 appsettings.json 以及appsettings.Development.json。对于Json文件,有一个参数是reloadOnChange,表示是否在文件修改后,重新读取并加载到内存里,设为true。 这段代码其实是没有必要的,这样改完代码还是得重启网站才能让设置生效,原因在强类型约束的时候使用的IOptions接口。 关于为什么显示指定reloadOnChange: true是没有必要的,可以做个简单测试: 我在appsettings.json里定义一个MySettings: { "Logging": { "LogLevel": { "Default": "Warning" } }, "MySettings": { "Message": ".NET Core Rocks!" }, "AllowedHosts": "*" } 建立对应的class public class MySettings { public string Message { get; set; } } 注册服务 public void ConfigureServices(IServiceCollection services) { //... services.Configure(Configuration.GetSection(nameof(MySettings))); } 依赖注入并输出结果 public class HomeController : Controller { protected IConfiguration Configuration; protected MySettings MySettings { get; set; } public HomeController( IOptions settings = null, IConfiguration configuration = null) { if (settings != null) MySettings = settings.Value; Configuration = configuration; } public IActionResult Index() { var m1 = MySettings.Message; var m2 = Configuration.GetSection("MySettings")["Message"]; return Content($"m1:{m1}, m2:{m2}"); } } 这时候我并没有写 reloadOnChange: true,看看运行结果: 结果当然两者是一样的。然后我们在运行时热修改配置值: 刷新网页,发现只有m2有变化。而这并不要求我显式指定reloadOnChange: true 要想让两者都取到最新的配置,使用上一节的方法,把m1的注入改成IOptionsSnapshot,现在再做热修改,两者都能立即生效: 破解谜团 刚才我们不指定reloadOnChange竟然也能做热修改,令人懵逼?我猜想,这个reloadOnChange,在最新版本的ASP.NET Core(2.2)中可能是默认启用的。关于这一点,我竟然没有找到官方的资料,不能确定这个参数的具体作用。但是ASP.NET Core是开源的,不妨来看看源代码: 代码位置:https://github.com/aspnet/Extensions 最终发现原来CreateDefaultBuilder()方法里,真的默认设置为reloadOnChange为true: 大家可以亲眼看看: https://github.com/aspnet/Extensions/blob/master/src/Hosting/Hosting/src/Host.cs 好奇(注孤生)的程序员终于在折腾开源代码后得到了满足…… 结论 ASP.NET Core 2.2 中如果要在运行时修改强类型配置,无需设置reloadOnChange = true,只需要使用IOptionsSnapshot接口即可大功告成! |
CopyRight 2018-2019 实验室设备网 版权所有 |