8.1 基础
1.传统Web.config配置的缺点,无法完成配置集群的管理
2.为了兼容传统的.NET Framework,仍然可以使用Web.config和ConfigurationManager类,但不推荐了
3..NET中的配置系统支持丰富的配置源,包括文件(json\xml\ini等)、注册表、环境变量、命令行、Azure Key Vault等,还可以配置自定义配置源。可以跟踪配置的改变,可以按照优先级覆盖。
8.1.1 Json文件配置

注意下面代码中optional false表示json文件存在就读取,不存在就不读 true表示不存在就报错
reloadOnChange:配置文件更改后是否重新加载。
Microsoft.Extensions.Configuration的使用
JSON文件:
{"AppConfig": {"DbConnection": "Server=;port=;database=","EnableTrace": false,"IpWhiteList": ["127.0.0.1","1.1.2.1","2.3.1.5"],"Port": 123,"ServiceName": "myapi"},"Student": [{"name": "yzk","age": 18},{"name": "albert","age": 18}],"Teacher": [{"name": "albertzhao","age": 25},{"name": "yangzhongke","age": 40}]}
代码:
using Microsoft.Extensions.Configuration;using System;using System.Collections;using System.Collections.Generic;using System.Linq;namespace _210722_Demon01_JsonConfigure {class Program {static void Main(string[] args) {ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();configurationBuilder.AddJsonFile("webconfig.json", true, true);IConfigurationRoot configurationRoot = configurationBuilder.Build();AppConfig appConfig = new AppConfig();//取子范围的一个元素值appConfig.DbConnection = configurationRoot["AppConfig:DbConnection"];//取子范围元素值的第二种写法,先获得一个域,域下面的["DbConnection"]appConfig.EnableTrace = configurationRoot.GetSection("AppConfig")["EnableTrace"];//取数组的写法 取AppConfig:IpWhiteList的全部子元素,选取子元素中的valueappConfig.IpWhiteList = (IEnumerable<string>)configurationRoot.GetSection("AppConfig:IpWhiteList").GetChildren().Select(x=>x.Value);foreach (var item in appConfig.IpWhiteList) {Console.WriteLine(item);}Console.ReadLine();}}class AppConfig {public string DbConnection { get; set; }public string EnableTrace { get; set; }public IEnumerable<string> IpWhiteList { get; set; }}}
8.1.2 Json序列化
https://www.json.cn/json/json2csharp.html Json转换为实体类
8.1.3 Json绑定读取配置(*)

用https://www.json.cn/json/json2csharp.html进行json转C#类,直接new实例,根节点的大类直接root.Get
using System;using System.Collections.Generic;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.Configuration.Json;namespace _210723_Demon01_JsonTransferClass {class Program {static void Main(string[] args) {ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();configurationBuilder.AddJsonFile("webconfig.json", false, true);var configurationRoot = configurationBuilder.Build();//绑定一个对象来进行转换Root root = configurationRoot.Get<Root>();AppConfig appConfig = configurationRoot.GetSection("AppConfig").Get<AppConfig>();Console.WriteLine(appConfig.DbConnection);Console.ReadLine();}}public class AppConfig {/// <summary>////// </summary>public string DbConnection { get; set; }/// <summary>////// </summary>public string EnableTrace { get; set; }/// <summary>////// </summary>public List<string> IpWhiteList { get; set; }/// <summary>////// </summary>public int Port { get; set; }/// <summary>////// </summary>public string ServiceName { get; set; }}public class StudentItem {/// <summary>////// </summary>public string name { get; set; }/// <summary>////// </summary>public int age { get; set; }}public class TeacherItem {/// <summary>////// </summary>public string name { get; set; }/// <summary>////// </summary>public int age { get; set; }}public class Root {/// <summary>////// </summary>public AppConfig AppConfig { get; set; }/// <summary>////// </summary>public List<StudentItem> Student { get; set; }/// <summary>////// </summary>public List<TeacherItem> Teacher { get; set; }}}
8.2 IOptionsSnapshot 选项配置


目录结构:
webconfig内容:
{"AppConfig": {"DbConnection": "Server=;port=;database=","EnableTrace": false,"IpWhiteList": ["127.0.0.1","1.1.2.1","2.3.1.5"],"Port": 55155,"ServiceName": "albertservice"},"Student": [{"name": "yzk","age": 18},{"name": "albert","age": 18}],"Teacher": [{"name": "albertzhao","age": 25},{"name": "yangzhongke","age": 40}]}
Root类:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace _210723_Demon02_JsonDIIOptionsSnapshot {public class Root {/// <summary>////// </summary>public AppConfig AppConfig { get; set; }/// <summary>////// </summary>public List<StudentItem> Student { get; set; }/// <summary>////// </summary>public List<TeacherItem> Teacher { get; set; }}public class AppConfig {/// <summary>////// </summary>public string DbConnection { get; set; }/// <summary>////// </summary>public string EnableTrace { get; set; }/// <summary>////// </summary>public List<string> IpWhiteList { get; set; }/// <summary>////// </summary>public int Port { get; set; }/// <summary>////// </summary>public string ServiceName { get; set; }}public class StudentItem {/// <summary>////// </summary>public string name { get; set; }/// <summary>////// </summary>public int age { get; set; }}public class TeacherItem {/// <summary>////// </summary>public string name { get; set; }/// <summary>////// </summary>public int age { get; set; }}}
IController接口和实现类以及扩展类TestControllerExtensions
interface IController {void ReadAppConfig();}using Microsoft.Extensions.Options;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace _210723_Demon02_JsonDIIOptionsSnapshot {class TestController : IController {public readonly IOptionsSnapshot<Root> optionsSnapshot;public TestController(IOptionsSnapshot<Root> optionsSnapshot) {this.optionsSnapshot = optionsSnapshot;}public void ReadAppConfig() {//此处注意IOptionsSanpshot.Value才是实例Console.WriteLine(optionsSnapshot.Value.AppConfig.Port);Console.WriteLine(optionsSnapshot.Value.AppConfig.ServiceName);}}}public static class TestControllerExtensions {public static void AddTestController(this IServiceCollection service) {service.AddScoped<IController, TestController>();}}
AppConfig类以及AppConfigExtensions类:
public class AppConfigController {public readonly IOptionsSnapshot<AppConfig> optionsSnapshot;public AppConfigController(IOptionsSnapshot<AppConfig> optionsSnapshot) {this.optionsSnapshot = optionsSnapshot;}public void ShowAppConfigPort() {Console.WriteLine(this.optionsSnapshot.Value.Port);}}public static class AppConfigControllerExtensions {public static void AddAppConfig(this IServiceCollection services) {services.AddScoped<AppConfigController>();}}
主程序:
new ServiceCollection—services.AddTestController()—new ConfigurationBuilder—configuretionBuilder.AddJson(xxx)—var rootConfig = configuretionBuilder.Build()—
services.AddOptions().Configure
此处必须将reloadOnChange设置为true,每次改变都要加载
using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;using System;namespace _210723_Demon02_JsonDIIOptionsSnapshot {class Program {static void Main(string[] args) {var services = new ServiceCollection();//依赖注入,注入TestController对象和AppConfigController对象services.AddTestController();services.AddAppConfig();//services.AddScoped<IController, TestController>();//services.AddScoped<AppConfigController>();ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();//此处必须将reloadOnChange设置为true,每次改变都要加载configurationBuilder.AddJsonFile("webconfig.json", false, true);var rootConfig = configurationBuilder.Build();//这边将rootConfig根节点绑定到Root对象上//将rootConfig的子域对象绑定到AppConfig对象services.AddOptions().Configure<Root>(e => rootConfig.Bind(e)).Configure<AppConfig>(e=>rootConfig.GetSection("AppConfig").Bind(e));using (var sp = services.BuildServiceProvider()) {//上面必须进行根节点对象绑定到Root上,不然无法将IOptionsSnapshot<Root>对象通过构造函数注入while (true) {//如果此处不进行sp.CreateScope(),即使修改了本地的webconfig.json的内容也无效using (var scope = sp.CreateScope()) {scope.ServiceProvider.GetRequiredService<IController>().ReadAppConfig();scope.ServiceProvider.GetService<AppConfigController>().ShowAppConfigPort();}Console.WriteLine("请按任意键继续");Console.ReadKey();}}//Console.ReadLine();}}}
8.3 其他配置提供者
8.3.1 命令行方式配置
·配置框架还支持命令行参数、环境变量等地方读取
·NuGet安装 Microsoft.Extension.Configuration.CommandLine
·configBuilder.AddCommandLine(args)
·参数支持多种格式,比如:server=127.0.0.1、—server=127.0.0.1(注意在键值之间加空格)、/server=127.0.0.1、/server 127.0.0.1(注意在键值之间加空格)。格式不能混用。
·调试的时候,VS中简化命令行传参数的方法。
代码在Gitee中necore项目210907——Demo01_OterConfigProvider项目
扁平化配置
如果是多级结构,通过:来分开 proxy:address=szdxzhy@outlook.com(这样来赋值)
如果是数组,则需要:0 :1 :2来配置
8.3.2 环境变量方式配置
下面图片写错了,包的名字为Microsoft.Extensions.Configuration.EnvironmentVariables
如果使用带参数的,如configBuilder.AddEnvironmentVariables(“Albert_”),则需要在环境变量中添加前缀,防止修改全局的环境变量。
8.3.4 其他配置源
8.3.5 多配置源
8.3.6 User-secrets机制
user-secrets的配置不放到源代码中,Nuget安装Microsoft.Extensions.Configuration.UserSecrets。
在VS项目上右键【管理用户机密】,编辑配置文件,configurationBuilder.AddUserSecrets
下图中usrsecrets放在普通配置文件之前:
//依赖注入的容器Collectionvar serviceCollection = new ServiceCollection();//注入Config和LogserviceCollection.AddConfigService();serviceCollection.AddLogService();serviceCollection.AddMailService();//设置OptionConfigurationBuilder configurationBuilder = new ConfigurationBuilder();//[多配置源问题--后面的配置覆盖前面的配置]//通过数据库来获取中心配置,先写死进行测试//SqlConnection需要安装Nuget:System.Data.SqlClient//AddDbConfiguration来自Zack.AnyDBConfigProviderstring strConfigFromSqlserver = "Server=192.168.0.238;Database=AlbertXDataBase;Trusted_Connection=True;";configurationBuilder.AddDbConfiguration(() => new SqlConnection(strConfigFromSqlserver),reloadOnChange: true,reloadInterval: TimeSpan.FromSeconds(2),tableName: "T_Configs");//从不泄密文件中读取账号密码:Secrets.JsonconfigurationBuilder.AddUserSecrets<Program>();//如果要启用本地Json文件读取,则启用下面的代码,通过AddJsonFile来加载相关扁平化配置信息。configurationBuilder.AddJsonFile("AlbertConfig/mailconfig.json", false, true);//控制台configurationBuilder.AddCommandLine(args);//环境变量configurationBuilder.AddEnvironmentVariables("Albert_");//从mailconfig读取回来的根节点var rootConfig = configurationBuilder.Build();//绑定根节点到MailKitRoot实体对象上//这边的GetSection里面的字段是Json字符串的字段,一定要注意这名字和实体类的属性名//一定要相同,不然无法绑定成功//ToDo:NetCore下的AddOption原理剖析。serviceCollection.AddOptions().Configure<MailKitRoot>(e => rootConfig.Bind(e)).Configure<MailBodyEntity>(e => rootConfig.GetSection("MailBodyEntity").Bind(e)).Configure<SendServerConfigurationEntity>(e => rootConfig.GetSection("SendServerConfigurationEntity").Bind(e));//使用DI,Build一个服务提供者using (var sp = serviceCollection.BuildServiceProvider()){var sendMailResult = sp.GetRequiredService<IMailService>().SendMail();Console.WriteLine(sendMailResult.ResultInformation);Console.WriteLine(sendMailResult.ResultStatus);}}
8.4 配置优先级
读取配置默认顺序,后者会覆盖前者:
现有的IConfiguration(一般不需要在这个前面加)
项目根目录下appsettings.json
项目根目录下appsettings.{Environment}.json
用户机密
环境变量
命令行参数
读取appsetting.json中的keyvalue,通常数据库连接字符串放在这边
{"Logging": {"LogLevel": {"Default": "Information","Microsoft": "Warning","Microsoft.Hosting.Lifetime": "Information"}},"AllowedHosts": "*","MyKey": "我是嘻嘻嘻"}
Startup.cs类想获取,想要注入IConfiguration
public Startup(IConfiguration configuration) {Configuration = configuration;}public IConfiguration Configuration { get; }
获取代码
乱码问题,需要将appsetting.json文件保存为UTF-8-无标签
VS设置“高级保存选项”:https://www.cnblogs.com/willingtolove/p/12121577.html
.NET3.1public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {if (env.IsDevelopment()) {app.UseDeveloperExceptionPage();}else {app.UseExceptionHandler("/Error");}app.Run(async context =>{//此处设置没啥用context.Response.ContentType = "text/plain;charset=utf-8";await context.Response.WriteAsync(Configuration["MyKey"]);});app.UseStaticFiles();app.UseRouting();app.UseAuthorization();app.UseEndpoints(endpoints => {endpoints.MapRazorPages();});}.NET6-Program.csvar builder = WebApplication.CreateBuilder(args);//内存缓存builder.Services.AddMemoryCache();var app = builder.Build();// Configure the HTTP request pipeline.if (app.Environment.IsDevelopment()){app.UseSwagger();app.UseSwaggerUI();}//运行环境读取方法if (app.Environment.EnvironmentName == "AlbertTest"){Console.WriteLine(app.Environment.EnvironmentName);}
通过命令行来配置参数,到项目目录下,cmd
dotnet run MyKey=”我是命令行参数”
8.5 开发SelfProvider
Reinvent the wheel 重新造轮子=> 价值是是什么?对于程序员而言,一定要有自己造轮子的能力。
从学习这到创造者!
8.5.1 开发web.config提供者
- FxConfigurationProvider
- 为项目添加Nuget包,Microsoft.Extensions.Configuration和Microsoft.Extensions.Configuration.FileExtensions
- 创建类FxConfigProvider,继承自FileConfigurationProvider抽象类
- 重写Load方法,其中Stream是文件流,从FileConfigurationSource中获取返回信息。

- 在Load方法中将字符串拍平,通常的格式是“{第一级名称}:第二级名称”作为键,第二级名称作为值,对应起来,如下图:

- FxConfigurationSource

同时在FxConfigurationProvider复写方法Load中,最后需要添加this.Data = data,将生成的字典赋值给它。
8.5.2 开发数据库配置提供者
中心化配置服务器
- 安装Sql Server:前往官网安装:https://www.microsoft.com/en-us/sql-server/sql-server-downloads
安装Developer或者基于云的,本机安装SSMS(https://docs.microsoft.com/zh-cn/sql/ssms/download-sql-server-management-studio-ssms?view=sql-server-ver15)进行数据库管理。验证数据库是否可以进行IP登录,如果不能按照如下配置并尝试关闭防火墙:数据库无法以IP登录问题解决。
- 配置数据库,登录进去后,建库建表,表三个字段:ID(自增主键),Name,Value。
ID设置:设置主键—是标识(双击即可)

- 将配置信息写入数据库中,Value支持Json格式

- 将Json映射成C#类

安装Nuget程序包:https://www.nuget.org/packages/Zack.AnyDBConfigProvider/
Install-Package Zack.AnyDBConfigProvider -Version 1.1.3Install-Package System.Data.SqlClient -Version 4.8.2
代码中调用:
string strConfigFromSqlserver = "Server=192.168.0.238;Database=AlbertXDataBase;Trusted_Connection=True;";configurationBuilder.AddDbConfiguration(() => new SqlConnection(strConfigFromSqlserver),reloadOnChange: true,reloadInterval: TimeSpan.FromSeconds(2));
8.6 配置系统综合案例
功能需求:
系统的主要配置放到配置专用的数据库中
- 连接配置数据库的连接字符串配置在用户机密中
- 把Smtp的配置显示到界面上
- 程序启动就连接Redis,并把Redis连接对象著恶策到依赖注入的系统中
操作:如何在Program.cs里面读取配置
在appsettings.json或者其他机密文件中添加数据库连接字符串
"SqlServer": {"ConnectStr": "Server = .; Database = AlbertConfigDb; Trusted_Connection = True;MultipleActiveResultSets=true;Connect Timeout=500"}
安装Zack.AnyDBConfigProvider包-安装System.Data.SqlClient
在Program中添加如下代码:
//Zack.AnyDBConfigProvider里面的GetConnectionString读取的字符串是配置文件中的//而不是数据库中的,连接上数据库后,AddDbConfiguration才是从数据库中读取Json//这里Host和WebHost一个是主机一个是通用主机//如果想要启用builder.Configuration.GetConnectionString("con");//则需要在appsettings.json中配置“ConnectionStrings:con":"xxx"builder.WebHost.ConfigureAppConfiguration((hostCtx, configBuilder) => {var env = hostCtx.HostingEnvironment;var connStr = builder.Configuration.GetValue<string>("SqlServer:ConnectStr");configBuilder.AddDbConfiguration(() =>new SqlConnection(connStr),reloadOnChange: true,reloadInterval: TimeSpan.FromSeconds(2),tableName: "ProduceToolConfig");//开发模式下,保存项目程序集到用户机密if (env.IsDevelopment() && !string.IsNullOrEmpty(env.ApplicationName)){var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));if (appAssembly != null){configBuilder.AddUserSecrets(appAssembly, optional: true);}}});
安装StackExchange.Redis包,这样就可以直接启动Redis了
//AddDbConfiguration之后即可从数据库中拿取Json对了builder.Services.AddSingleton<IConnectionMultiplexer>(sp =>{//在Program.cs中读取配置的一种方法var connStr = builder.Configuration.GetValue<string>("RedisServer:Configuration");return ConnectionMultiplexer.Connect(connStr);});
读取数据库中配置信息,直接绑定到SmtpSettings类上
public class SmtpSettings{public string ServerName { get; set; }public string UserName { get; set; }public string Password { get; set; }}//配置选项:Smtp 注意这里的根是appsettings.jsonbuilder.Services.AddOptions().Configure<SmtpSettings>(smtp => builder.Configuration.GetSection("SmtpSettings").Bind(smtp));//调用using AlbertZhao.cn.Models;using Microsoft.AspNetCore.Http;using Microsoft.AspNetCore.Mvc;using Microsoft.Extensions.Options;using StackExchange.Redis;namespace AlbertZhao.cn.Controllers{[Route("api/[controller]/[action]")][ApiController]public class SmtpController : ControllerBase{private readonly ILogger<SmtpController> logger;//日志服务private readonly IOptionsSnapshot<SmtpSettings> options;//配置选项服务private readonly IConnectionMultiplexer connectionMultiplexer;//Redis服务public SmtpController(ILogger<SmtpController> logger, IOptionsSnapshot<SmtpSettings> options, IConnectionMultiplexer connectionMultiplexer){this.logger = logger;this.options = options;this.connectionMultiplexer = connectionMultiplexer;}[HttpGet]public ActionResult<SmtpSettings?> GetSmtpInfo(){logger.LogInformation("开始获取数据");return new SmtpSettings() { ServerName = options.Value.ServerName ,UserName = options.Value.UserName ,Password = options.Value.Password};}[HttpGet]public ActionResult<string?> GetRedisInfo(){logger.LogInformation("开始测试Redis");var ping = connectionMultiplexer.GetDatabase(0).Ping();return ping.ToString();}}}
