在很久以前,还是单服务器的时候,而且服务器还部署在我们自己的服务器上,我对配置框架基本不怎么了解,因为配置都是定死的,基本上很难有变动,如今在公司开发的项目是微服务的,有很多的服务器,而且支持用户自己去写url,port这种配置,因此熟悉了一下.Net core的配置框架,看看怎么样可以灵活的部署项目。
读取配置的功能主要用.Net Core写好的实现就可以了。
using System.Collections.Generic;
namespace Microsoft.Extensions.Configuration
{
public class ConfigurationBuilder : IConfigurationBuilder
{
public ConfigurationBuilder();
public IDictionary<string, object> Properties { get; }
public IList<IConfigurationSource> Sources { get; }
public IConfigurationBuilder Add(IConfigurationSource source);
public IConfigurationRoot Build();
}
}
.Net Core 在Microsoft.Extensions.Configuration包下加了IConfigurationBuilder的很多拓展方法用来支持不同的配置方式。
内存配置模式
public void MemoryCollectionConfiguration()
{
var builder = new ConfigurationBuilder();
builder.AddInMemoryCollection(new Dictionary<string, string>()
{
{ "section1:key1","value1"},
{ "key2", "key2"},
{ "section1:key3","value3"},
});
var configurationRoot = builder.Build();
var section1 = configurationRoot.GetSection("section1");
var key1 = section1["key1"];
var key2 = configurationRoot["key2"];
var key3 = configurationRoot["section1:key3"];
Console.WriteLine(key1); // value1
Console.WriteLine(key2); // key2
Console.WriteLine(key3); // value3
}
命令行参数模式
launchSettings.json
"StartWeb": {
"commandName": "Project",
"commandLineArgs": "CommandLineKey1=value1 --CommandLineKey2=value2 CommandLineKey3=value3 -k1=k3",
"launchBrowser": true,
"launchUrl": "weatherforecast",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"Key1": "1"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
可以在lanuchSettings中添加命令行参数。
public void CommandLineConfiguration(string[] args)
{
var builder = new ConfigurationBuilder();
var mapper = new Dictionary<string, string> { { "-k1", "CommandLineKey1" } };
builder.AddCommandLine(args, mapper);
var configurationRoot = builder.Build();
var key1 = configurationRoot["CommandLineKey1"];
var key2 = configurationRoot["CommandLineKey2"];
var key3 = configurationRoot["CommandLineKey3"];
Console.WriteLine(key1); // k3
Console.WriteLine(key2); // value2
Console.WriteLine(key3); // value3
}
环境变量配置
在容器环境下,比如Docker或者K8S,因为容器之间具有隔离性,所以采用环境变量来配置的情况也是有很多的。
public void EnviromentVariables()
{
var builder = new ConfigurationBuilder();
builder.AddEnvironmentVariables();
var configurationRoot = builder.Build();
var keyEnvironment = configurationRoot["ASPNETCORE_ENVIRONMENT"];
var key1 = configurationRoot["Key1"];
var java_home = configurationRoot["JAVA_HOME"];
Console.WriteLine(keyEnvironment); // Development
Console.WriteLine(key1); // 1
Console.WriteLine(java_home); // D:\jdk\jdk8
}
可以在lanuchSettings中添加环境变量。
"StartWeb": {
"commandName": "Project",
"commandLineArgs": "CommandLineKey1=value1 --CommandLineKey2=value2 CommandLineKey3=value3 -k1=k3",
"launchBrowser": true,
"launchUrl": "weatherforecast",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"Key1": "1"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
文件配置
这个配置我用得最多,无论什么环境下都很好用,而且配置起来很直观,用的最多的文件类型应该就是json了,其他的如xml,ini,yml等都是相似的。
public void FileConfiguration()
{
var builder = new ConfigurationBuilder();
builder.AddJsonFile("appsettings.Development.json", optional: false, reloadOnChange: false);
var configurationRoot = builder.Build();
var Default = configurationRoot["Logging:LogLevel:Default"];
Console.WriteLine(Default); // Information
}
json文件
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
监听配置源变化
如何监听数据源的变化还有有必要先了解一下接口。
通过前面的代码我们可以发现,不同种类的配置信息都是通过Add.....方法添加进builder的,那么就很有必要看一下IConfigurationBuilder接口的Add方法了。
public IConfigurationBuilder Add(IConfigurationSource source);
看一下参数和返回值
public interface IConfigurationSource
{
IConfigurationProvider Build(IConfigurationBuilder builder);
}
IConfigurationSource接口就非常的简单,返回一个Provider。
public interface IConfigurationProvider
{
IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath);
IChangeToken GetReloadToken();
void Load();
void Set(string key, string value);
bool TryGet(string key, out string value);
}
发现了含有关键字的GetReloadToken,这个Token或许会用来唯一标识数据源,那么还缺一个OnReload方法来告诉框架数据源发生了改变。自己实现起来是有一点麻烦的,还好已经有一个写好的类了,我们直接使用Microsoft.Extensions.Configuration.ConfigurationProvider。
public abstract class ConfigurationProvider : IConfigurationProvider
{
protected ConfigurationProvider();
protected IDictionary<string, string> Data { get; set; }
public virtual IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath);
public IChangeToken GetReloadToken();
public virtual void Load();
public virtual void Set(string key, string value);
public override string ToString();
protected void OnReload();
}
注意一个属性一个方法。
protected IDictionary<string, string> Data { get; set; }
protected void OnReload();
很明显数据放在Data里,调用OnReload方法的时候就会触发自己注册的委托。
首先实现IConfigurationSource
class MyConfigurationSource : IConfigurationSource
{
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new MyConfigurationProvider();
}
}
接下来实现一个会变化的数据源
class MyConfigurationProvider : ConfigurationProvider, IConfigurationProvider
{
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);
}
void Load(bool reload)
{
this.Data["lastTime"] = DateTime.Now.ToString();
if (reload)
{
base.OnReload();
}
}
}
使用
public void HotConfiguration()
{
var builder = new ConfigurationBuilder();
builder.Add(new MyConfigurationSource());
var configRoot = builder.Build();
var lastTime = configRoot["lastTime"];
Console.WriteLine(lastTime);
ChangeToken.OnChange(() => configRoot.GetReloadToken(), () =>
{
Console.WriteLine(configRoot["lastTime"]);
});
}
2021/8/23 23:28:54
2021/8/23 23:28:57
2021/8/23 23:29:00
2021/8/23 23:29:03
每三秒变更一次。
当然我们可以更加像厂商提供的那样来进行注册,比如
builder.AddJsonFile("appsettings.Development.json")
方法很简单,用个委托方法就行了。
namespace Microsoft.Extensions.Configuration
{
public static class MyConfigurationBuilderExtensions
{
public static IConfigurationBuilder AddMyConfiguration(this IConfigurationBuilder builder)
{
builder.Add(new MyConfigurationSource());
return builder;
}
}
}
使用修改一下
public void HotConfiguration()
{
var builder = new ConfigurationBuilder();
builder.AddMyConfiguration();
var configRoot = builder.Build();
var lastTime = configRoot["lastTime"];
Console.WriteLine(lastTime);
ChangeToken.OnChange(() => configRoot.GetReloadToken(), () =>
{
Console.WriteLine(configRoot["lastTime"]);
});
}
这样就很像了,厂商大概也都是这么实现的。
感谢您能读到这里,祝您生活幸福美满。