核心扩展点
- IConfigurationSource
- IConfigurationProvider
我们之前提到过,配置框架的扩展点主要是依赖以上2个接口,下面我们分别来看一下接口的具体用法。
IConfigurationSource
// // 摘要: // Represents a source of configuration key/values for an application. public interface IConfigurationSource { // // 摘要: // Builds the Microsoft.Extensions.Configuration.IConfigurationProvider for this // source. // // 参数: // builder: // The Microsoft.Extensions.Configuration.IConfigurationBuilder. // // 返回结果: // An Microsoft.Extensions.Configuration.IConfigurationProvider IConfigurationProvider Build(IConfigurationBuilder builder); }
从接口定义我们知道,该接口包含一个Build方法,入参是一个IConfigurationBuilder,返回一个IConfigurationProvider对象。
IConfigurationProvider
// // 摘要: // Provides configuration key/values for an application. public interface IConfigurationProvider { // // 摘要: // Returns the immediate descendant configuration keys for a given parent path based // on this Microsoft.Extensions.Configuration.IConfigurationProviders data and the // set of keys returned by all the preceding Microsoft.Extensions.Configuration.IConfigurationProviders. // // 参数: // earlierKeys: // The child keys returned by the preceding providers for the same parent path. // // parentPath: // The parent path. // // 返回结果: // The child keys. IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath); // // 摘要: // Returns a change token if this provider supports change tracking, null otherwise. // // 返回结果: // The change token. IChangeToken GetReloadToken(); // // 摘要: // Loads configuration values from the source represented by this Microsoft.Extensions.Configuration.IConfigurationProvider. void Load(); // // 摘要: // Sets a configuration value for the specified key. // // 参数: // key: // The key. // // value: // The value. void Set(string key, string value); // // 摘要: // Tries to get a configuration value for the specified key. // // 参数: // key: // The key. // // value: // The value. // // 返回结果: // True if a value for the specified key was found, otherwise false. bool TryGet(string key, out string value); }
从定义可以看出,该接口包含数个方法,其中包括获取配置变更的方法及配置加载的方法。其实,在Microsoft.Extensions.Configuration中有一个实现了该接口的抽象方法ConfigurationProvider类,我们一般都是继承该抽象类来实现我们自定义的配置提供程序,而不是直接实现IConfigurationProvider接口。
下面,我们通过代码来演示我们自定义的配置数据源。
首先,我们定义一个MyConfigurationProvider类,该类继承了抽象类ConfigurationProvider,并重写了Load方法用来加载配置数据源。我们在类中定义一个方法Load(bool reload),方法通过一个参数来确定是否重新加载数据源,以便我们通过一个定时任务来模拟配置的变更与重新加载,具体的代码如下所示
class MyConfigurationProvider : ConfigurationProvider { Timer timer; public MyConfigurationProvider():base() { timer = new Timer() ; timer.Elapsed += Timer_Elapsed; timer.Interval = 3000; timer.Start(); } private void Timer_Elapsed(object sender, ElapsedEventArgs e) { Load(true); } public override void Load() { Load(false); } private void Load(bool reload) { this.Data["time"] = System.DateTime.Now.ToString(); if (reload) { base.OnReload(); } } }
这样,我们就可以在程序启动时,显示当前时间,并每3秒就重新加载时间到配置,并显示出来。
IConfigurationProvider定义好了之后,我们来创建IConfigurationSource对象来生成定义的MyConfigurationProvider。
class MyConfigurationSource : IConfigurationSource { public IConfigurationProvider Build(IConfigurationBuilder builder) { return new MyConfigurationProvider(); } }
这样,我们就可以在创建IConfigurationBuilder对象后,通过add方法来添加该数据源。
configurationBuilder.Add(new MyConfigurationSource());
这样,当执行IConfigurationBuilder.Build方法时,就可将IConfigurationSource集合内的数据源全部生成到IConfigurationRoot配置根,以通过key-value方式来访问。
和之前一样,为了代码结构更加合理,以及实现封闭开放原则,我们对刚刚的add方法进行封装,以隐藏其具体实现,而只暴露操作接口
public static class MyConfigurationSourceExtension { public static IConfigurationBuilder AddSource( this IConfigurationBuilder configurationBuilder) { MyConfigurationSource myConfigurationSource = new MyConfigurationSource(); configurationBuilder.Add(myConfigurationSource); return configurationBuilder; } }
这样,我们的调用将更加方便简洁
configurationBuilder.AddSource();
通过以上过程,我们完成了数据源的配置,但是,还没有实现对配置变更的监听,因此,我们还需要实现我们的ChangeToken.OnChange方法来监听我们的配置变更。那么,具体的program.cs代码如下
static void Main(string[] args) { IConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); //configurationBuilder.Add(new MyConfigurationSource()); configurationBuilder.AddSource(); IConfigurationRoot configurationRoot= configurationBuilder.Build(); ChangeToken.OnChange(()=> configurationRoot.GetReloadToken(), () => { Console.WriteLine(configurationRoot["time"]); }); Console.ReadKey(); }
好的,到这里我们本节的内容就结束了,我们本节主要通过配置框架的2个扩展点IConfigurationSource和IConfigurationProvider来实现自定义的配置数据源,这样,我们就可以低成本的实现我们自定义的配置方案。
对于这些基本的框架类东西,有时间的话还是动手敲一下,有助于加深理解,大佬就略过吧。
详细代码请参阅
https://github.com/IronMarmot/Samples/tree/master/CoreSamples