DotNet Configuration 源码: https:// github.com/dotnet/runti me/tree/master/src/libraries ,其中以 Microsoft.Extensions.Configuration 开头的项目
Configuration 官方文档: https:// docs.microsoft.com/en-u s/dotnet/core/extensions/configuration 、 https:// docs.microsoft.com/en-u s/aspnet/core/fundamentals/configuration/?view=aspnetcore-5.0
Nuget包:Microsoft.Extensions.Configuration
内存配置
IConfigurationRoot configuration = new ConfigurationBuilder()
// 添加内存配置
.AddInMemoryCollection(new Dictionary<string, string>
{
["KeyName1"] = "KeyValue1"
})
.Build();
/// 获取配置
Console.WriteLine(configuration["KeyName1"]); // KeyValue1
文件配置
Nuget包:
- Json:
Microsoft.Extensions.Configuration.Json
- Ini:
Microsoft.Extensions.Configuration.Ini
- Xml:
Microsoft.Extensions.Configuration.Xml
假设项目中有如下3个文件:
a.json文件
{
"Key": "KeyValue",
"Person": {
"Name": "MyName",
"Age": 10
}
}
a.xml 文件
<Configuration>
<Key>KeyValue</Key>
<Person>
<Name>MyName</Name>
<Age>10</Age>
</Person>
</Configuration>
a.ini 文件
Key = KeyValue
[Person]
Name = My Name
Age = 10
C#
// JSON 文件配置
IConfiguration jsonConfiguration = new ConfigurationBuilder()
.AddJsonFile("a.json") // 添加 Json 文件配置
.Build();
Console.WriteLine(jsonConfiguration["Key"]); // KeyValue
// 使用 ":" 分割 "父节" 与 "子节"
Console.WriteLine(jsonConfiguration["Person:Name"]); // MyName
Console.WriteLine(jsonConfiguration["Person:Age"]); // 10
// XML 文件配置
IConfiguration xmlConfiguration = new ConfigurationBuilder()
.AddXmlFile("a.xml") // 添加 Xml 文件配置
.Build();
Console.WriteLine(xmlConfiguration["Key"]); // KeyValue
Console.WriteLine(xmlConfiguration["Person:Name"]); // MyName
Console.WriteLine(xmlConfiguration["Person:Age"]); // 10
// Ini 文件配置
IConfiguration iniConfiguration = new ConfigurationBuilder()
.AddIniFile("a.ini") // 添加 Ini 文件配置
.Build();
Console.WriteLine(iniConfiguration["Key"]); // KeyValue
Console.WriteLine(iniConfiguration["Person:Name"]); // MyName
Console.WriteLine(iniConfiguration["Person:Age"]); // 10
可选文件配置
默认配置文件是不可选的,文件必须存在,否则会抛出异常,通过设置第二个参数让配置文件是可选的
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("a.optional.json",true /* 可选配置文件 */)
.Build();
在文件内容改变时重新加载配置
默认情况下文件内容改变时不会重新加载配置,通过设置第三个参数让文件内容改变时重新加载配置
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("a.json", false, true)
.Build();
do
{
Console.WriteLine(configuration["Key"]);
var consoleKeyInfo = Console.ReadKey();
if (consoleKeyInfo.Key == ConsoleKey.Q)
{
Console.WriteLine("Quit");
break;
}
} while (true);
分层配置
配置是分 "层" 的,父节与子节之间通过":"分割
IConfiguration configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string>
{
["KeyName1:SubKey:SubKey2"] = "SubKeyValue",
["KeyName1:SubKey"] = "SubKeyValue2",
["KeyName1:SubKey"] = "OverrideSubKeyValue" // 覆盖
})
.Build();
Console.WriteLine(configuration["KeyNaKeyName1:SubKey:SubKey2me1"]); // SubKeyValue
Console.WriteLine(configuration["KeyNaKeyName1:SubKey"]); // OverrideSubKeyValue
当存在相同的Key时,后面的值会覆盖前面的值,例如上方实例中的 Key 为 KeyName1:SubKey 的值被覆盖了
IConfigurationSection
IConfigurationSection接口继承子IConfiguration,添加了如下属性
- Key:键名
- Path:完整的路径
- Value:值
IConfiguration::GetSection 获取节
IConfiguration configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string>
{
["KeyName1"] = "KeyValue1",
["KeyName1:SubKey1"] = "SubKeyValue1",
["KeyName1:SubKey2"] = "SubKeyValue2",
["KeyName1:SubKey3:A"] = "A",
}).Build();
// 获取指定子Section
IConfiguration section = configuration.GetSection("KeyName1");
Console.WriteLine(JsonSerializer.Serialize(section));
// {"Key":"KeyName1","Path":"KeyName1","Value":"KeyValue1"}
// 获取子Section中的配置
Console.WriteLine(section["SubKey1"]); // SubKeyValue1
还有一个GetRequiredSection
方法,与GetSection
唯一不同的是,当要获取的配置节不存在时会抛出异常
IConfigurationSection::Exist 判断节是否存在
IConfiguration configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string>
{
["KeyName1"] = "KeyValue1
}).Build();
Console.WriteLine(configuration.GetSection("ABC").Exist()); // False
Console.WriteLine(configuration.GetSection("KeyName1").Exist()); // True
IConfiguration::GetChildren 获取全部子节
IConfiguration configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string>
{
["KeyName1"] = "KeyValue1",
["KeyName1:SubKey1"] = "SubKeyValue1",
["KeyName1:SubKey2"] = "SubKeyValue2",
["KeyName1:SubKey3:A"] = "A",
}).Build();
// 获取全部子Section
IEnumerable<IConfiguration> sections = configuration.GetSection("KeyName1").GetChildren();
Console.WriteLine(JsonSerializer.Serialize(sections));
/*
[
{"Key":"SubKey1","Path":"KeyName1:SubKey1","Value":"SubKeyValue1"},
{"Key":"SubKey2","Path":"KeyName1:SubKey2","Value":"SubKeyValue2"},
{"Key":"SubKey3","Path":"KeyName1:SubKey3","Value":null}
]
*/
// 获取全部子Section
var sections2 = configuration.GetSection("KeyName1:SubKey3").GetChildren();
Console.WriteLine(JsonSerializer.Serialize(sections2));
/*
[
{"Key":"A","Path":"KeyName1:SubKey3:A","Value":"A"}
]
*/
Configuration Chain,配置链,将已存在的配置添加到配置
将已存在的配置添加到配置中,链接到一起
IConfiguration configuration1 = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string>
{
["A"] = "A Value"
})
.Build();
IConfiguration configuration2 = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string>
{
["B"] = "B Value"
})
.Build();
IConfiguration configuration = new ConfigurationBuilder()
.AddConfiguration(configuration1)
.AddConfiguration(configuration2)
.Build();
Console.WriteLine($"A:{configuration["A"]}");
Console.WriteLine($"B:{configuration["B"]}");
Connection Strings,连接字符串
在 http://Asp.Net 连接字符串配置几乎必不可少,官方专门定义了一个配置的扩展方法,来获取连接字符串
连接字符串以ConnectionStrings
为父节
IConfiguration configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string>
{
["ConnectionStrings:Default"] = "Default ConnectingString",
["ConnectionStrings:SqlServer"] = "SqlServer ConnectingString",
["ConnectionStrings:PostgreSql"] = "PostgreSql ConnectingString",
})
.Build();
Console.WriteLine($"Default ConnectionString:{configuration.GetConnectionString("Default")}");
Console.WriteLine($"Default SqlServer:{configuration.GetConnectionString("SqlServer")}");
Console.WriteLine($"Default PostgreSql:{configuration.GetConnectionString("PostgreSql")}");
Configuration Bind,配置绑定
Nuget包:Microsoft.Extensions.Configuration.Binder
类似于将配置反序列化到对象
C# 1
class ConfigurationModel2
{
public string A { get; set; }
public string B { get; set; }
private string C { get; set; }
public string GetC()
{
return C;
}
}
C# 2
IConfiguration configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string>
{
["MyBind:A"] = "A Value",
["MyBind:B"] = "B Value",
["MyBind:C"] = "C Value",
})
.Build();
绑定当前配置到对象实例
var myBind = new ConfigurationModel2
{
A = "A Ini Value",
B = "B Ini Value",
};
configuration.GetSection("MyBind").Bind(myBind);
Console.WriteLine(myBind.A); // A Value
Console.WriteLine(myBind.B); // B Value
Console.WriteLine(myBind.GetC()); // Null,默认不会绑定到非 public属性
绑定时指定 Key
var myBind2 = new ConfigurationModel2();
configuration.Bind("MyBind", myBind2);
Console.WriteLine(myBind2.A); // A Value
Console.WriteLine(myBind2.B); // B Value
Console.WriteLine(myBind2.GetC()); // Null
绑定非 public 属性
var myBind3 = new ConfigurationModel2();
configuration.GetSection("MyBind").Bind(myBind3, bindOption => { bindOption.BindNonPublicProperties = true; // 设置绑定非 public 属性 });
Console.WriteLine(myBind3.A); // A Value
Console.WriteLine(myBind3.B); // B Value
Console.WriteLine(myBind3.GetC()); // C Value
IConfiguration::GetValue 获取指定键的值,并转换为指定类型
支持的类型包括:int、uint、short、ushort、long、ulong、bool、byte、sbyte、char、decimal、double、float、DateTime、DateTimeOffset、TimeSpan、Uri、Guid
实例 ( 实例类型与数据来自于官方测试代码 ):
IConfigurationRoot configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string>
{
["int"] = "2147483647",
["uint"] = "4294967295",
["short"] = "32767",
["ushort"] = "65535",
["long"] = "-9223372036854775808",
["ulong"] = "18446744073709551615",
["bool"] = "trUE",
["byte"] = "255",
["sbyte"] = "127",
["char"] = "uffff",
["decimal"] = "79228162514264337593543950335",
["double"] = "1.79769e+308",
["float"] = "3.40282347E+38",
["DateTime"] = "2015-12-24T07:34:42-5:00",
["DateTimeOffset"] = "12/24/2015 13:44:55 +4",
["TimeSpan"] = "99.22:22:22.1234567",
["Uri"] = "http://www.bing.com",
["Guid"] = "CA761232-ED42-11CE-BACD-00AA0057B223",
}).Build();
Console.WriteLine(configuration.GetValue<int>("int")); // 2147483647
Console.WriteLine(configuration.GetValue<uint>("uint")); // 4294967295
Console.WriteLine(configuration.GetValue<short>("short")); // 32767
Console.WriteLine(configuration.GetValue<ushort>("ushort")); // 65535
Console.WriteLine(configuration.GetValue<long>("long")); // -9223372036854775808
Console.WriteLine(configuration.GetValue<ulong>("ulong")); // 18446744073709551615
Console.WriteLine(configuration.GetValue<bool>("bool")); // True
Console.WriteLine(configuration.GetValue<byte>("byte")); // 255
Console.WriteLine(configuration.GetValue<sbyte>("sbyte")); // 127
Console.WriteLine(configuration.GetValue<char>("char")); //
Console.WriteLine(configuration.GetValue<decimal>("decimal")); // 79228162514264337593543950335
Console.WriteLine(configuration.GetValue<double>("double")); // 1.79769E+308
Console.WriteLine(configuration.GetValue<float>("float")); // 3.4028235E+38
Console.WriteLine(configuration.GetValue<DateTime>("DateTime")); // 12/24/2015 8:34:42 PM
Console.WriteLine(configuration.GetValue<DateTimeOffset>("DateTimeOffset")); // 12/24/2015 1:44:55 PM +04:00
Console.WriteLine(configuration.GetValue<TimeSpan>("TimeSpan")); // 99.22:22:22.1234567
Console.WriteLine(configuration.GetValue<Uri>("Uri")); // http://www.bing.com/
Console.WriteLine(configuration.GetValue<Guid>("Guid")); // ca761232-ed42-11ce-bacd-00aa0057b223
GetValue 提供默认值
Console.WriteLine(configuration.GetValue<int>("int2", -1 /* 默认值 */));
IConfiguration::Get() 绑定配置到指定类型
支持 GetValue
支持的全部类型,支持绑定数组
class ConfigurationModel
{
public int Int { get; set; }
public float Float { get; set; }
public Uri Uri { get; set; }
public Guid Guid { get; set; }
public string[] Strings { get; set; }
}
class Program
{
static void Main(string[] args)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string>
{
["int"] = "2147483647",
["float"] = "3.40282347E+38",
["Uri"] = "http://www.bing.com",
["Guid"] = "CA761232-ED42-11CE-BACD-00AA0057B223",
["Strings:0"] = "Value 0",
["Strings:1"] = "Value 1",
["Strings:2"] = "Value 2"
}).Build();
ConfigurationModel model = configuration.Get<ConfigurationModel>();
Console.WriteLine(JsonSerializer.Serialize(model));
/*
{
"Int": 2147483647,
"Float": 3.4028235E+38,
"Uri": "http://www.bing.com",
"Guid": "ca761232-ed42-11ce-bacd-00aa0057b223"
"Strings": [
"Value 0",
"Value 1",
"Value 2"
]
}
*/
}
}
命令行配置,将命令行参数数组args
添加到配置
Nuget包:Microsoft.Extensions.Configuration.CommandLine
支持如下形式的命令行配置:
- 参数与值通过
=
分割 - 参数使用
/
前缀,参数与值通过=
或者空格分割 - 参数使用
--
前缀,参数与值通过=
或者空格分割
值可以加双引号或单引号,比如当值中包含特殊字符( 如空格 ),就必须要加双引号或单引号
实例:
class Program
{
static void Main(string[] args)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.AddCommandLine(args) // 从命令行添加配置
.Build();
Console.WriteLine($"args:{String.Join(',', args)}");
Console.WriteLine(configuration["a"]);
Console.WriteLine(configuration["b"]);
Console.WriteLine(configuration["c"]);
Console.WriteLine(configuration["d"]);
Console.WriteLine(configuration["e"]);
Console.WriteLine(configuration["f"]);
Console.WriteLine(configuration["g"]);
}
}
运行程序:
dotnet run -- a=av b="b v" /c cv /d=dv --e=ev --f fv -g gv
输出如下
args:a=av,b=b v,/c,cv,/d=dv,--e=ev,--f,fv,-g,gv
av
b v
cv
dv
ev
fv
交换映射,实现命令行配置的别名与简短名
假设有如下命令行配置
- name:名称
- n:name的简短名
- file:文件
- outputFile:file的别名
- f:file的简短名
交换映射的字典键必须以"-"或"--"开头
- -:表示简短名
- --:表示别名
实例:
class Program
{
static void Main(string[] args)
{
IDictionary<string, string> switchMappings = new Dictionary<string, string>
{
["-n"] = "name",
["-f"] = "file",
["--outputFile"] = "file",
};
IConfigurationRoot configuration = new ConfigurationBuilder()
.AddCommandLine(args, switchMappings)
.Build();
Console.WriteLine($"args:{String.Join(',', args)}");
Console.WriteLine($"name:{configuration["name"]}");
Console.WriteLine($"file:{configuration["file"]}");
}
}
UserSecret,用户密钥配置,将用户密钥天添加到配置
Nuget包:Microsoft.Extensions.Configuration.UserSecrets
UserSecret介绍
将密码等配置保存在电脑的secrets.json
文件中,而不是在项目文件里
在Windows系统中,它的位置在
%APPDATA%MicrosoftUserSecrets<user_secrets_id>secrets.json
在Linux、macOS系统中,它的存储位置在
~/.microsoft/usersecrets/<user_secrets_id>/secrets.json
这样就可以实现在不同的电脑上有不同的配置信息
使用 UserSecret 配置
使用 UserSecret 配置前,需要指定 UserSecretId,UserSecretId 为 GUID 格式
secrets.json
文件的文件夹名称就是UserSecretId
在项目配置中指定 UserSecretId
运行命令:dotnet user-secrets init
运行完成后将自动在项目配置文件<ProjectName>.csproj
中生成 UserSecretsId
然后在参数中传入项目的程序集
IConfiguration configuration = new ConfigurationBuilder()
.AddUserSecrets(Assembly.GetExecutingAssembly()) // 将用户密钥天添加到配置
.Build();
Console.WriteLine($"test-key:{configuration["my-key"]}");
直接在参数中指定UserSecretId
IConfiguration configuration = new ConfigurationBuilder()
.AddUserSecrets("8B348FF5-ED73-41B7-8769-1CEF70421DEC")
.Build();
Console.WriteLine($"test-key:{configuration["my-key"]}");
AddUserSecrets
与AddJson
一样也是加载文件配置,所以也有可选配置参数和重新加载配置文件的参数
UserSecret工具的使用
user-secrets 工具有如下命令
- init:初始化,为项目设置一个 UserSecretId 启用密钥配置
- clear:清除项目密钥配置
- set:设置密钥配置
dotnet user-secrets set my-key value
- remove:移除密钥配置
dotnet user-secrets remove my-key
- list:查看密钥配置
环境变量配置,将环境变量信息添加到配置
Nuget包:Microsoft.Extensions.Configuration.EnvironmentVariables
实例:
IConfiguration configuration = new ConfigurationBuilder()
.AddEnvironmentVariables() // 将环境变量信息添加到配置
.Build();
Console.WriteLine($"path:{configuration["PATH"]}");
环境变量前缀
可以指定环境变量前缀,将只会加载此前缀的环境变量
实例:
假设有如下环境变量
- MyPrefix_A:A Value
- MyPrefix_B:B Value
- MyPrefix2_A2:A Value 2
- MyPrefix2_B2:B Value 2
IConfiguration configuration = new ConfigurationBuilder()
.AddEnvironmentVariables("MyPrefix_")
.AddEnvironmentVariables("MyPrefix2_")
.Build();
Console.WriteLine($"path:{configuration["A"]}"); // A Value
Console.WriteLine($"path:{configuration["B"]}"); // B Value
Console.WriteLine($"path:{configuration["A2"]}"); // A Value 2
Console.WriteLine($"path:{configuration["A2"]}"); // B Value 2