基于选项模式实现.NET Core的配置热更新


基于选项模式实现.NET Core的配置热更新文章插图
作者 | 秦元培
出品 | CSDN(ID:CSDNnews)
头图 | CSDN 下载自东方 IC
最近在面试的时候 , 遇到了一个关于 .NET Core 配置热更新的问题 , 顾名思义 , 就是在应用程序的配置发生变化时 , 如何在不重启应用的情况下使用当前配置 。 从 .NET Framework 一路走来 , 对于 Web.Config 以及 App.Config 这两个配置文件 , 我们应该是非常熟悉了 , 通常情况下 ,IIS 会检测这两个配置文件的变化 , 并自动完成配置的加载 , 可以说它天然支持热更新 , 可当我们的视野伸向分布式环境的时候 , 这种配置方式就变得繁琐起来 , 因为你需要修改一个又一个配置文件 , 更不用说这些配置文件可能都是放在容器内部 。 而有经验的朋友 , 可能会想到 , 利用 Redis 的发布-订阅来实现配置的下发 , 这的确是一个非常好的思路 。 总而言之 , 我们希望应用可以随时感知配置的变化 , 所以 , 在今天这篇博客里 , 我们来一起聊聊 .NET Core 中配置热更新相关的话题 , 这里特指全新的选项模式(Options) 。
基于选项模式实现.NET Core的配置热更新文章插图
Options三剑客在 .NET Core 中 , 选项模式(Options)使用类来对一组配置信息进行强类型访问 , 因为按照接口分隔原则(ISP)和关注点分离这两个工程原则 , 应用的不同部件的配置应该是各自独立的 , 这意味着每一个用于访问配置信息的类 , 应该是只依赖它所需要的配置信息的 。 举一个简单的例子 , 虽然 Redis 和 MySQL 都属于数据持久化层的设施 , 但是两者属于不同类型的部件 , 它们拥有属于各自的配置信息 , 而这两套配置信息应该是相互独立的 , 即 MySQL 不会因为 Redis 的配置存在问题而停止工作 。 此时 , 选项模式(Options)推荐使用两个不同的类来访问各自的配置 。 我们从下面这个例子开始:
{ "Learning": { "Years": 5, "Topic": [ "Hotfix", ".NET Core", "Options" ], "Skill": [ { "Lang": "C#", "Score": 3.9 }, { "Lang": "Python", "Score": 2.6 }, { "Lang": "JavaScript", "Score": 2.8 } ] }}此时 , 如果希望访问 Learning节点下的信息 , 我们有很多种实现方式:
//方式1var learningSection = Configuration.GetSection("Learning");var careerYears = learningSection.GetValue("Years");var topicHotfix = learningSection.GetValue("Topic:0");//方式2var careerYears = Configuration["Learning:Years"];var topicHotfix = Configuration["Learning:Topic:0");而更好的方式是 , 定义一个类来访问这组配置信息:
[Serializable]public class LearningOptions{ public decimal Years { get; set; } public List Topic { get; set; } public List Skill { get; set; }}[Serializable]public class SkillItem{ public string Lang { get; set; } public decimal? Score { get; set; }}同样地 , 茴香的茴字有几种写法 , 你可知道?
//写法1:手动绑定var leaningOptions = new LearningOptions;Configuration.GetSection("Learning").Bind(leaningOptions);//写法2:自动绑定leaningOptions = Configuration.GetSection("Learning").Get;//写法3:自动绑定 + 依赖注入services.Configure(Configuration.GetSection("Learning"));//写法4:配置的二次加工services.PostConfigure(options => options.Years += 1);//写法5:委托绑定services.Configure(options =>{ options.AppName = "ASP.NET Core"; options.AppVersion = "1.2.1";});我们知道 , 在 .NET Core 里依赖注入被提升到了一等公民的位置 , 可谓是无处不在 。 当我们在 IoC 容器中注入 LearningOptions以后 , 就可以在服务层或者控制器层直接使用它们 , 此时 , 我们就会遇到传说中的 Options 三剑客 , 即IOptions、IOptionsSnapshot和IOptionsMonitor 。 关于它们三个的区别 , 官方文档里给出了详细的说明: