上文书说到了WebApplicationBuilder,以及4个步骤的第一步-CreateBuilder。本文按照5个对象4个步骤的顺序继续往下讲,至于WebApplication后续还会出现,届时再详细介绍。
当前步骤:
var builder = WebApplication.CreateBuilder(args);builder.Configuration.XXX();

1.干啥的
1.1 真身
在.NET中,Configuration(配置)是一个用于管理应用程序设置的对象。它允许从多种异构数据源(如Json文件、环境变量、命令行参数,自定义配置源等)读取配置信息,并提供统一的API来访问这些配置,说白了,它的作用就是读取配置,然后再吐出这些配置给逻辑代码使用的。
在.NET8中,配置对象Configuration的核心是IConfiguration接口,而WebApplication.CreateBuilder(args)方法会初始化一个ConfigurationManager,它实现了IConfigurationBuilder和IConfiguration接口,用于构建和存储配置。dotnet源码:WebApplication.CreateBuilder()创建了ConfigurationManager

而我们使用的builder.Configuration其实就是ConfigurationManager

ConfigurationManager的源码在dotnet/runtime中,命名空间:Microsoft.Extensions.Configuration

而IConfigurationManager继承自IConfigurationBuilder和IConfiguration

– 严丝合缝
记忆:
builder.Configuration(dotnet中) ->
ConfigurationManager(runtime中)->
IConfigurationManager(runtime中) ->
IConfigurationBuilder&IConfiguration(runtime中)
1.2 作用
Configuration 是 .NET 中的应用程序配置管理系统,它负责:
- 管理应用程序的所有配置信息,怎么管理?统一管理呗;
- 支持多种异构配置源(文件、环境变量、数据库、Azure keyvault等);
- 支持配置热更新和变更通知;
1.3 祛魅
Configuration 就是.NET中,程序自动读取你指定的配置信息,然后再给你提供几个方法,在程序中任意地方获取它读取到的配置,供你的逻辑代码使用。就像你,先喝水(读取配置信息),溜达到某个地方,放水(输出配置信息)。
2. 怎么用
先-配置
再-读
2.1 配置
2.1.1 多环境配置
配置源的加载顺序决定了优先级,后加载的配置源会覆盖先加载的同键值,默认顺序如下:
- appsettings.json
- .AddJsonFile(文件名,文件是否可选加载,是否热加载);
- appsettings.{Environment}.json
- 用于配置特定环境,如prod,dev,test
- AddJsonFile(文件名,文件是否可选加载,是否热加载);
- 用户机密(仅开发环境)
- builder.Configuration.AddUserSecrets();
- 环境变量
- builder.Configuration.AddEnvironmentVariables(“MYPP_”);
- 命令行参数
- builder.Configuration.AddCommandLine(args);
- 自定义配置源
- builder.Configuration.AddCustomConfiguration();
源码中,在WebApplication.CreateBuilder()中,初始化ConfigurationManager时已经默认添加了配置源,喏:

当然,你也必须可以手动添加,也是我们当前知识点的主线任务之一
//Configurationbuilder.Configuration
//基础文件配置
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
//特定环境配置
.AddJsonFile($"appsettins.{builder.Environment.EnvironmentName}.json", optional: false, reloadOnChange: true) //环境变量配置
.AddEnvironmentVariables("MYAPP_")
//命令行配置
.AddCommandLine(args);
//用户自定义源配置
.AddCustomConfigurtion()
//用户机密配置,仅限于开发环境
if (builder.Environment.IsDevelopment()){
builder.Configuration.AddUserSecrets<Program>();
}
2.1.2 appsettings.json
appsettings.json和appsettings.{Environment}.json用法比较简单,不再细说。当然,除了json以外还可以添加xml和INI:
- AddXmlFile()
- AddIniFile()
2.1.3 用户机密
AddUserSecrets此方法通常只在开发环境中使用,在开发过程中安全存储敏感数据(如连接字符串,API密钥等)。避免将敏感信息提交到源代码仓库。
创建用户机密只需右键项目->管理用户机密。或者在Program.cs同级目录下secret.json中修改。
2.1.4 环境变量 AddEnvironmentVariables
这个方法可以将带有特定前缀的环境变量添加到配置中,如MYAPP_,并在添加到配置中后,去掉特定前缀。如设置环境变量MYAPP_ConnectionString,则在配置中可以通过键ConnectionString获取。
使用场景:
- 容器化部署(Docker, Kubernetes)
- 云服务平台(Azure, AWS, GCP)
- CI/CD流水线配置
- 不同环境(开发、测试、生产)的配置隔离
2.1.5 命令行
AddCommandLine添加命令行参数到配置系统中。允许在启动应用程序时通过命令行参数来覆盖其他配置源的设置。常用于调试或者某些自动化的脚本中。如启动时输入命令:
// 运行应用时传入参数:
// dotnet run --urls=“https://localhost:7000” --Environment=“Staging” --Logging:LogLevel:Default=“Debug”
2.1.6 自定义配置源 AddCustomConfiguration
自定义一个配置源,加载一个自定义的字典:
实现IConfigurationSource接口(以上配置源都对应一个souce,都是基于这个接口来实现的):
using Microsoft.Extensions.Configuration;
public class CustomConfigurationSource : IConfigurationSource{
private readonly Dictionary<string, string> _data;
public CustomConfigurationSource(Dictionary<string, string> data)
{
_data = data;
}
public IConfigurationProvider Build(IConfigurationBuilder builder) {
return new CustomConfigurationProvider(_data);
}}
返回实现了IConfigurationProvider的提供程序:
using System.Collections.Generic;
using Microsoft.Extensions.Configuration;
public class CustomConfigurationProvider : ConfigurationProvider
{
private readonly Dictionary<string, string> _data;
public CustomConfigurationProvider(Dictionary<string, string> data)
{
_data = data;
}
public override void Load()
{
// 将内存中的数据加载到配置中
foreach (var item in _data)
{
Data[item.Key] = item.Value;
}
}}
扩展下IConfigurationBuilder接口,起个看起来像样子的名字:
public static class CustomConfigurationExtensions
{
public static IConfigurationBuilder AddCustomConfiguration(this IConfigurationBuilder builder, Dictionary<string, string> data)
{
return builder.Add(new CustomConfigurationSource(data));
}
}
使用自定义源
var builder = WebApplication.CreateBuilder(args);
// 添加其他配置源...
// 自定义配置源
var customConfig = new Dictionary<string, string>{ ["Custom:Key1"] = "Value1", ["Custom:Key2"] = "Value2"};builder.Configuration.AddCustomConfiguration(customConfig);
2.2 读
2.2.1.直接读 builder.Configuration[]
- 简单读取
- 分层键读取(冒号分割)
var builder = WebApplication.CreateBuilder(args);
// 简单键值读取
var appName = builder.Configuration["Application:Name"];var version = builder.Configuration["Application:Version"];
// 分层键读取(冒号分隔)
var connectionString = builder.Configuration["Database:ConnectionStrings:Default"];var logLevel = builder.Configuration["Logging:LogLevel:Default"];
2.2.2 节点读 GetSection
很显然,除了GetSection,还有GetChildren
var builder = WebApplication.CreateBuilder(args);
// 获取配置节
var databaseSection = builder.Configuration.GetSection("Database");var connectionString = databaseSection["ConnectionString"];
var timeout = databaseSection["Timeout"];
// 遍历配置节
var loggingSection = builder.Configuration.GetSection("Logging:LogLevel");
foreach (var child in loggingSection.GetChildren())
{
Console.WriteLine($"{child.Key}: {child.Value}");
}
2.2.3 强类型绑定 POCO
public class DatabaseOptions
{
public string ConnectionString { get; set; } = string.Empty;
public int Timeout { get; set; } = 30;
public bool EnableRetry { get; set; } = true;}
public class ApplicationOptions
{
public string Name { get; set; } = string.Empty;
public string Version { get; set; } = string.Empty;
public List<string> SupportedCultures { get; set; } = new();
}
- 直接绑定 GetSection().Bind(object)
// 方式1:直接绑定
var dbOptions = new DatabaseOptions();builder.Configuration.GetSection("Database").Bind(dbOptions);
- 泛型绑定 GetSection().Get()
// 方式2:泛型绑定(推荐)
var dbOptions = builder.Configuration.GetSection("Database").Get<DatabaseOptions>();
- 选项模式(依赖注入) 企业级应用
// 方式3:选项模式(依赖注入)
builder.Services.Configure<DatabaseOptions>(builder.Configuration.GetSection("Database"));builder.Services.Configure<ApplicationOptions>(builder.Configuration.GetSection("Application"));
以上的读只是读的一种,这种方式使我们在启动流程中获取相应的配置,然后根据需要初始化服务然后注入到容器中,如:
var builder = WebApplication.CreateBuilder(args);
// 从Configuration中获取值
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
// 注册服务时使用配置
builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString));
还有一种读,就是我们在Controller中获取到IConfiguration对象,然后从中读取到我们需要的配置信息,如:
[ApiController][Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IConfiguration _configuration;
public ProductsController(IConfiguration configuration)
{
_configuration = configuration;
}
[HttpGet]
public IActionResult GetProducts()
{
// 直接读取配置(不推荐 - 缺乏类型安全)
var pageSize = _configuration.GetValue<int>("Pagination:PageSize", 10);
var enableCaching = _configuration.GetValue<bool>("Features:EnableCaching", true);
// 使用配置值
return Ok(new { PageSize = pageSize, EnableCaching = enableCaching });
}
}
但是这种做法不推荐,一是不简洁,二是缺乏安全类型。POCO,也就是强类型绑定是推荐的做法。这块会在builder.Service.Configure中做介绍。
3. 源码
简单叙述几个重要对象:
- IConfigurationSource
- IConfigurationProvider
- IConfigurationBuilder
- IConfigurationRoot
- IConfiguration
1.IConfigurationSource是个接收器,负责接收外部配置源。需实现其Build方法,该方法把外部配置源传递给自定义实现IConfigurationProvider;- 先接收;

2.IConfigurationProvider就是个读取器,它会加载传入的外部配置源信息;一个接收器对应一个读取器;- 再加载;

3.IConfigurationBuilder是个IConfigurationSource的收集器,通过Add方法把外部配置源放到一个List里,别忘了,builder.Configuration的Configuration继承了IConfigurationBuilder,所以直接Add;- 按先接收再加载的套路重复加入其他配置源;


4.IConfigurationRoot又是个provider的收集器,它会把所有的provider收集起来,供通过键查询配置的时候使用;

在这儿收集的;

5.IConfiguration中包含索引器、GetSection、GetChildren等方法,这些方法通过键读取对应的配置,别忘了ConfigurationManager继承自IConfiguration,所以ConfigurationManager拥有以上能力;

ConfigurationManager:

6.所以我们在Program.cs里可以直接通过builder.Configuration.GetSection和builder.Configuration[“key”]获取到配置。闭环。

1176

被折叠的 条评论
为什么被折叠?



