references:
youtube-yzk
microsoft-configuration
.NET中的配置系统支持丰富的配置源,包括文件(json、xml、ini等)、注册表、环境变量、命令行、Azure Key Vault等,还可以配置自定义配置源。可以跟踪配置的改变,可以按照优先级覆盖。
Json文件配置:
1.创建一个Json文件,文件名随意,比如config.json
2.NuGet安装Microsoft.Extensions.Configuration和Microsoft.Extensions.Configuration.Json
3.编写代码,读取配置. (这里读的是程序运行的目录下的文件,而不是源代码中的文件)
using Microsoft.Extensions.Configuration;
ConfigurationBuilder configurationBuilder= new ConfigurationBuilder();
configurationBuilder.AddJsonFile("config.json", optional: false, reloadOnChange: true);
IConfigurationRoot configRoot = configurationBuilder.Build();
string name = configRoot["name"];
Console.WriteLine(name);
string address = configRoot.GetSection("proxy:address").Value;
Console.WriteLine(address);
绑定读取配置:
1.可以绑定一个类,自动完成配置的读取。
2.NuGet安装:Microsoft.Extensions.Configuration.Binder
using Microsoft.Extensions.Configuration;
ConfigurationBuilder configurationBuilder= new ConfigurationBuilder();
configurationBuilder.AddJsonFile("config.json", optional: false, reloadOnChange: true);
IConfigurationRoot configRoot = configurationBuilder.Build();
//也可以直接从root去get一个根结点的类,前提是这个泛型和json结构一致
Proxy proxy = configRoot.GetSection("proxy").Get<Proxy>();
Console.WriteLine($"{proxy.Address}, {proxy.Port}");
class Proxy
{
public string Address {get; set;}
public int Port {get; set;}
}
选项方式读取:
1.推荐使用选项方式读取,和DI结合更好,且更好利用reloadonchange机制
2.NuGet安装:Microsoft.Extensions.OPtions以及上面安装的其他三个拓展包
3.读取配置的时候,DI要声明IOptions、IOptionsMonitor , IOptionsSnapshot等类型. IOptions不会读取到新的值;和IOptionsMonitor相比,IOptionsSnapshot会在同一个范围内(比如一个request中)保持一致。建议使用IOptionsSnapshot。
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
IServiceCollection services = new ServiceCollection();
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddJsonFile("config.json", optional: false, reloadOnChange: true);
IConfigurationRoot configRoot = configurationBuilder.Build();
// options 先添加到DI框架, IOptions{model}就可以被注入了。
// 然后把Config对象绑定到根节点上去,Configure<绑定的类型>(哪个对象绑定)
services.AddOptions().Configure<Config>(e => configRoot.Bind(e))
.Configure<Proxy>(e => configRoot.GetSection("proxy").Bind(e));
services.AddScoped<TestController>();
services.AddScoped<TestController2>();
using (var sp = services.BuildServiceProvider())
{
while (true)
{
using (var scope = sp.CreateScope())
{
// scope改变,snapshot就会改变配置
var c = scope.ServiceProvider.GetRequiredService<TestController>();
c.Test();
// scope不变,snapshot就不会改变配置
var c2 = sp.GetRequiredService<TestController2>();
c2.Test();
}
Console.WriteLine("press any button");
Console.ReadLine();
}
}
class Config
{
public string Name { get; set; }
public int Age { get; set; }
public Proxy Proxy { get; set; }
}
class Proxy
{
public string Address { get; set; }
public int Port { get; set; }
}
using Microsoft.Extensions.Options;
class TestController
{
private readonly IOptionsSnapshot<Config> optConfig;
public TestController(IOptionsSnapshot<Config> optConfig)
{
this.optConfig = optConfig;
}
public void Test()
{
Console.WriteLine(optConfig.Value.Age);
Console.WriteLine("********");
}
}
using Microsoft.Extensions.Options;
class TestController2
{
private readonly IOptionsSnapshot<Proxy> optConfig;
public TestController2(IOptionsSnapshot<Proxy> optConfig)
{
this.optConfig = optConfig;
}
public void Test()
{
Console.WriteLine(optConfig.Value.Address);
Console.WriteLine("********");
}
}
除了JSON文件配置,还有其他配置方式:
命令行方式配置:
1.配置框架还支持从命令行参数、环境变量等地方读取。
2.NuGet安装Microsoft.Extensions.Configuration.CommandLine
3.configBuilder.AddCommandLine(args)
4.参数支持多种格式,server=127.0.0.1、 —server=127.0.0.1、—server 127.0.0.1
CommandLine方式的配置,在程序运行时就确定了,所以没有运行时改配置的问题。
对于{"A" : {"B": "b", "C": "c"}}这种结构,命令行配置没有直接的配置方式(key=value),可以采用扁平化配置。
1.对于环境变量、命令行等简单的键值对结构,如果想要进行复杂结构的配置,需要进行“扁平化处理”。对于配置的名字需要采用层级配置。例如:a🅱️c=jjj, 对于数组:a🅱️c:0=j, a🅱️c:1=k
环境变量配置:
1.NuGet安装:Microsoft.Extensions.Configuration.EnvironmentVariables
2.configurationBuilder.AddEnvironmentVariables(), AddEnvironmentVariables有无参数和有prefix参数的两个重载。无参数版本会把程序相关的所有环境变量都加载进来,由于有可能和系统中已有的环境变量冲突,因此建议用有prefix参数的函数。读取配置时,prefix参数会被忽略,例如 C1_name,读取的时候属性还是name。
3.VS调试的时候,避免修改环境变量,直接在vs中设置。
自定义配置解析:
这里解析了一个web.config的文件,主要的过程是:
- 首先在configurationBuilder中去添加对应的配置源,这里采用的是FxConfigSource,类似于json、命令行等配置源,在Build函数中,会返回一个对应的provider。
- FxConfigProvider就是刚刚添加数据源的对应的解析类,解析的过程中,将数据源的格式转换成框架使用的扁平格式,如A:B:C:D,这样系统就可以认识这个配置了(this.Data)。
- 调用configurationBuilder.Build函数,这个函数就是调用了配置provider的load函数,将数据解析到框架中
- 通过Options、DI,将WebConfig这个类和解析的数据进行构建和绑定。当需要使用的时候通过DI构造并注入到需要使用的类中,就可以使用这些配置了。
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
ServiceCollection services = new ServiceCollection();
services.AddScoped<TestWebConfig>();
ConfigurationBuilder configurationBuilder= new ConfigurationBuilder();
configurationBuilder.AddUserSecrets<Program>();
configurationBuilder.AddFxConfig("web.config");
// configurationBuilder.AddCommandLine(args);
IConfigurationRoot configurationRoot = configurationBuilder.Build();
services.AddOptions().Configure<WebConfig>(e => configurationRoot.Bind(e));
using (var sp = services.BuildServiceProvider())
{
var c = sp.GetRequiredService<TestWebConfig>();
c.Test();
}
using Microsoft.Extensions.Configuration;
static class FxConfigExtensions
{
public static IConfigurationBuilder AddFxConfig(this IConfigurationBuilder builder, string path = null)
{
return builder.Add(new FxConfigSource() { Path = path });
}
}
using Microsoft.Extensions.Configuration;
class FxConfigSource : FileConfigurationSource
{
public override IConfigurationProvider Build(IConfigurationBuilder builder)
{
EnsureDefaults(builder);
return new FxConfigProvider(this);
}
}
using System.Xml;
using Microsoft.Extensions.Configuration;
class FxConfigProvider : FileConfigurationProvider
{
public FxConfigProvider(FxConfigSource source) : base(source)
{
}
public override void Load(Stream stream)
{
var data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(stream);
var csNodes = xmlDocument.SelectNodes("/configuration/connectionStrings/add");
if (csNodes != null)
{
foreach (XmlNode xmlNode in csNodes.Cast<XmlNode>())
{
string name = xmlNode.Attributes["name"].Value;
string connectionString = xmlNode.Attributes["connectionString"].Value;
data[$"{name}:connectionString"] = connectionString;
var providerName = xmlNode.Attributes["providerName"];
if (providerName != null)
{
data[$"{name}:providerName"] = providerName.Value;
}
}
}
var asNodes = xmlDocument.SelectNodes("/configuration/appSettings/add");
if (asNodes != null)
{
foreach(XmlNode xmlNode in asNodes.Cast<XmlNode>())
{
string key = xmlNode.Attributes["key"].Value;
key = key.Replace(".", ":");
string value = xmlNode.Attributes["value"].Value;
data[key] = value;
}
}
this.Data = data;
}
}
class WebConfig
{
public connectionStr Conn1 { get; set; }
public connectionStr Conn2 { get; set;}
public Config Config{ get; set;}
}
class connectionStr
{
public string connectionString { get; set; }
public string providerName { get; set; }
}
class Config
{
public string Name { get; set; }
public string Age { get; set; }
public Proxy proxy{ get; set; }
}
class Proxy
{
public string Address { get; set; }
public string Port { get; set; }
public string[] ids { get; set; }
}
<configuration>
<connectionStrings>
<add name="conn1" connectionString="sdfsdsdf" providerName="abc"/>
<add name="conn2" connectionString="ewqerqweq" providerName="sql"/>
</connectionStrings>
<appSettings>
<add key="Config:name" value="yzk"/>
<add key="Config:proxy:address" value="mxncvnxmcn"/>
<add key="Config:proxy:prot" value="123123"/>
<add key="Config:proxy:ids:0" value="0"/>
<add key="Config:proxy:ids:1" value="1"/>
</appSettings>
</configuration>
配置全部写到源代码中,可以被泄漏:
1.可以将配置写入本地环境变量
2.user-secrets(开发过程中的不应该泄漏的配置,不会加密配置,只适用开发)
- .NET提供了user-secrets机制,user-secrets的配置不放到源代码中。
- NuGet安装:Microsoft.Extensions.Configuration.UserSecrets
- 在项目中查看配置文件,会自动在csproj中的UserSecretsId就是文件夹的名字
- configBuilder.AddUserSecrets() 相关安装使用文档:https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-9.0&tabs=linux
Top comments (0)