在软件开发中,配置是指应用程序运行时可调整的参数集合,如数据库连接字符串、API 地址、日志级别等。将这些参数从代码中分离出来,便于在不修改代码的情况下调整应用行为。C# 提供了多种配置管理方式,从传统的 XML 配置文件到现代的多源配置系统,每种方式都有其适用场景。本文将全面介绍 C# 中的配置技术,帮助开发者根据项目需求选择合适的配置方案。
硬编码配置存在诸多问题:
良好的配置管理应具备:
C# 配置技术经历了多个阶段:
.NET Framework
中的app.config
和web.config
.NET Core
引入的新配置系统,支持多源配置、依赖注入等.NET Framework
传统配置方式.NET Framework
应用使用 XML 格式的配置文件:
app.config
(编译后生成[程序名].exe.config
)web.config
典型的app.config
结构:
<configuration>
<appSettings>
<add key="MaxRetries" value="3" />
<add key="LogLevel" value="Info" />
<add key="ApiUrl" value="https://api.example.com" />
appSettings>
<connectionStrings>
<add name="DefaultConnection"
connectionString="Server=localhost;Database=Test;Integrated Security=True"
providerName="System.Data.SqlClient" />
connectionStrings>
<system.web>
system.web>
configuration>
使用System.Configuration
命名空间下的ConfigurationManager
类读取配置,需引用System.Configuration
程序集。
using System;
using System.Configuration;
class TraditionalConfigDemo
{
static void Main()
{
// 读取appSettings配置
string maxRetries = ConfigurationManager.AppSettings["MaxRetries"];
string logLevel = ConfigurationManager.AppSettings["LogLevel"];
string apiUrl = ConfigurationManager.AppSettings["ApiUrl"];
Console.WriteLine($"最大重试次数: {maxRetries}");
Console.WriteLine($"日志级别: {logLevel}");
Console.WriteLine($"API地址: {apiUrl}");
// 读取连接字符串
ConnectionStringSettings connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"];
if (connectionString != null)
{
Console.WriteLine($"连接字符串: {connectionString.ConnectionString}");
Console.WriteLine($"提供程序: {connectionString.ProviderName}");
}
}
}
对于复杂配置,可以定义自定义配置节:
<configuration>
<configSections>
<section name="EmailSettings" type="ConfigDemo.EmailSettingsSection, ConfigDemo" />
configSections>
<EmailSettings>
<SmtpServer address="smtp.example.com" port="587" />
<Credentials username="[email protected]" password="password" />
<Options enableSsl="true" timeout="30000" />
EmailSettings>
configuration>
对应的 C# 类:
using System.Configuration;
// 自定义配置节
public class EmailSettingsSection : ConfigurationSection
{
[ConfigurationProperty("SmtpServer")]
public SmtpServerElement SmtpServer => (SmtpServerElement)this["SmtpServer"];
[ConfigurationProperty("Credentials")]
public CredentialsElement Credentials => (CredentialsElement)this["Credentials"];
[ConfigurationProperty("Options")]
public OptionsElement Options => (OptionsElement)this["Options"];
}
// 配置元素
public class SmtpServerElement : ConfigurationElement
{
[ConfigurationProperty("address", IsRequired = true)]
public string Address => (string)this["address"];
[ConfigurationProperty("port", DefaultValue = 25)]
public int Port => (int)this["port"];
}
public class CredentialsElement : ConfigurationElement
{
[ConfigurationProperty("username", IsRequired = true)]
public string Username => (string)this["username"];
[ConfigurationProperty("password", IsRequired = true)]
public string Password => (string)this["password"];
}
public class OptionsElement : ConfigurationElement
{
[ConfigurationProperty("enableSsl", DefaultValue = false)]
public bool EnableSsl => (bool)this["enableSsl"];
[ConfigurationProperty("timeout", DefaultValue = 10000)]
public int Timeout => (int)this["timeout"];
}
// 读取自定义配置节
class CustomConfigDemo
{
static void Main()
{
EmailSettingsSection emailSettings =
(EmailSettingsSection)ConfigurationManager.GetSection("EmailSettings");
if (emailSettings != null)
{
Console.WriteLine($"SMTP服务器: {emailSettings.SmtpServer.Address}:{emailSettings.SmtpServer.Port}");
Console.WriteLine($"用户名: {emailSettings.Credentials.Username}");
Console.WriteLine($"启用SSL: {emailSettings.Options.EnableSsl}");
}
}
}
.NET Core
/.NET 5 +
现代配置系统.NET Core 引入了全新的配置系统,具有以下特点:
默认配置源及优先级(从低到高):
appsettings.json
appsettings.[Environment].json
(如appsettings.Development.json
)创建appsettings.json
文件(设置 “复制到输出目录” 为 “如果较新则复制”):
{
"AppSettings": {
"MaxRetries": 3,
"LogLevel": "Info",
"ApiUrl": "https://api.example.com"
},
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=Test;Integrated Security=True"
},
"EmailSettings": {
"SmtpServer": {
"Address": "smtp.example.com",
"Port": 587
},
"Credentials": {
"Username": "[email protected]",
"Password": "password"
},
"Options": {
"EnableSsl": true,
"Timeout": 30000
}
}
}
安装必要的 NuGet 包:
Install-Package Microsoft.Extensions.Configuration
Install-Package Microsoft.Extensions.Configuration.Json
Install-Package Microsoft.Extensions.Configuration.EnvironmentVariables
Install-Package Microsoft.Extensions.Configuration.CommandLine
读取配置:
using System;
using Microsoft.Extensions.Configuration;
using System.IO;
class ConsoleConfigDemo
{
static void Main(string[] args)
{
// 构建配置
IConfiguration config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
.AddEnvironmentVariables()
.AddCommandLine(args)
.Build();
// 直接读取配置
string maxRetries = config["AppSettings:MaxRetries"];
string apiUrl = config["AppSettings:ApiUrl"];
string connectionString = config["ConnectionStrings:DefaultConnection"];
Console.WriteLine($"最大重试次数: {maxRetries}");
Console.WriteLine($"API地址: {apiUrl}");
Console.WriteLine($"连接字符串: {connectionString}");
// 读取嵌套配置
string smtpAddress = config["EmailSettings:SmtpServer:Address"];
int smtpPort = int.Parse(config["EmailSettings:SmtpServer:Port"]);
Console.WriteLine($"SMTP服务器: {smtpAddress}:{smtpPort}");
}
}
将配置绑定到实体类更便于使用:
using Microsoft.Extensions.Configuration;
// 定义实体类
public class AppSettings
{
public int MaxRetries { get; set; }
public string LogLevel { get; set; }
public string ApiUrl { get; set; }
}
public class ConnectionStrings
{
public string DefaultConnection { get; set; }
}
public class SmtpServerSettings
{
public string Address { get; set; }
public int Port { get; set; }
}
public class CredentialsSettings
{
public string Username { get; set; }
public string Password { get; set; }
}
public class EmailOptions
{
public bool EnableSsl { get; set; }
public int Timeout { get; set; }
}
public class EmailSettings
{
public SmtpServerSettings SmtpServer { get; set; }
public CredentialsSettings Credentials { get; set; }
public EmailOptions Options { get; set; }
}
// 绑定并使用配置
class ConfigBindingDemo
{
static void Main(string[] args)
{
IConfiguration config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
// 绑定到实体类
AppSettings appSettings = new AppSettings();
config.GetSection("AppSettings").Bind(appSettings);
ConnectionStrings connectionStrings = new ConnectionStrings();
config.GetSection("ConnectionStrings").Bind(connectionStrings);
EmailSettings emailSettings = config.GetSection("EmailSettings").Get<EmailSettings>(); // 另一种绑定方式
// 使用绑定后的配置
Console.WriteLine($"最大重试次数: {appSettings.MaxRetries}");
Console.WriteLine($"连接字符串: {connectionStrings.DefaultConnection}");
Console.WriteLine($"SMTP服务器: {emailSettings.SmtpServer.Address}:{emailSettings.SmtpServer.Port}");
Console.WriteLine($"启用SSL: {emailSettings.Options.EnableSsl}");
}
}
ASP.NET Core
中的配置ASP.NET Core
自动构建配置系统,可直接注入IConfiguration
使用:
// 在Program.cs中(ASP.NET Core 6+)
var builder = WebApplication.CreateBuilder(args);
// 配置已自动加载,可在此处添加额外配置源
builder.Configuration.AddIniFile("appsettings.ini", optional: true);
var app = builder.Build();
// 在控制器中使用
app.MapGet("/config", (IConfiguration config) =>
{
var logLevel = config["AppSettings:LogLevel"];
var connectionString = config["ConnectionStrings:DefaultConnection"];
return new
{
LogLevel = logLevel,
ConnectionString = connectionString
};
});
app.Run();
在控制器中使用:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
public class ConfigController : Controller
{
private readonly IConfiguration _config;
// 注入IConfiguration
public ConfigController(IConfiguration config)
{
_config = config;
}
public IActionResult Index()
{
string apiUrl = _config["AppSettings:ApiUrl"];
// 使用配置...
return View();
}
}
选项模式是.NET Core
推荐的配置使用方式,通过强类型访问配置,提供更好的封装和可测试性。
定义选项类:
using Microsoft.Extensions.Options;
// 选项类
public class AppSettingsOptions
{
public const string AppSettings = "AppSettings";
public int MaxRetries { get; set; }
public string LogLevel { get; set; }
public string ApiUrl { get; set; }
}
public class EmailSettingsOptions
{
public const string EmailSettings = "EmailSettings";
public SmtpServerSettings SmtpServer { get; set; }
public CredentialsSettings Credentials { get; set; }
public EmailOptions Options { get; set; }
}
在依赖注入中配置选项:
// 控制台应用
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json");
IConfiguration config = builder.Build();
// 创建服务集合
var services = new ServiceCollection();
// 配置选项
services.Configure<AppSettingsOptions>(config.GetSection(AppSettingsOptions.AppSettings));
services.Configure<EmailSettingsOptions>(config.GetSection(EmailSettingsOptions.EmailSettings));
// 注册需要使用选项的服务
services.AddSingleton<MyService>();
// 构建服务提供器
using (var serviceProvider = services.BuildServiceProvider())
{
var myService = serviceProvider.GetRequiredService<MyService>();
myService.DoWork();
}
使用选项:
public class MyService
{
private readonly AppSettingsOptions _appSettings;
private readonly IOptions<EmailSettingsOptions> _emailSettings;
// 注入选项
public MyService(
IOptions<AppSettingsOptions> appSettings,
IOptions<EmailSettingsOptions> emailSettings)
{
_appSettings = appSettings.Value;
_emailSettings = emailSettings;
}
public void DoWork()
{
Console.WriteLine($"最大重试次数: {_appSettings.MaxRetries}");
Console.WriteLine($"SMTP服务器: {_emailSettings.Value.SmtpServer.Address}");
}
}
.NET Core
提供三种选项接口,适用于不同场景:
IOptions:
IOptionsSnapshot:
IOptionsMonitor:
OnChange
方法监听配置变化// 使用IOptionsMonitor监听配置变化
public class MonitorService
{
private readonly IOptionsMonitor<AppSettingsOptions> _monitor;
private IDisposable _changeToken;
public MonitorService(IOptionsMonitor<AppSettingsOptions> monitor)
{
_monitor = monitor;
// 监听配置变化
_changeToken = _monitor.OnChange((newValue, name) =>
{
Console.WriteLine($"配置已变化: 新的最大重试次数 {newValue.MaxRetries}");
});
}
public void ShowSettings()
{
Console.WriteLine($"当前日志级别: {_monitor.CurrentValue.LogLevel}");
}
// 清理资源
public void Dispose()
{
_changeToken?.Dispose();
}
}
环境变量是容器化部署(如 Docker、Kubernetes)中常用的配置方式:
// 添加环境变量配置源
var config = new ConfigurationBuilder()
.AddEnvironmentVariables()
.Build();
// 读取环境变量
// 环境变量名通常使用下划线分隔,如AppSettings__MaxRetries对应配置中的AppSettings:MaxRetries
string maxRetries = config["AppSettings__MaxRetries"];
在 Docker 中设置环境变量:
ENV AppSettings__MaxRetries=5
ENV ConnectionStrings__DefaultConnection="Server=db;Database=Test;User Id=sa;Password=password"
命令行参数可用于临时覆盖配置:
// 添加命令行配置源
var config = new ConfigurationBuilder()
.AddCommandLine(args)
.Build();
运行程序时传递参数:
dotnet MyApp.dll --AppSettings:MaxRetries 5 --ConnectionStrings:DefaultConnection "Server=..."
INI 文件适合简单的键值对配置:
; appsettings.ini
[AppSettings]
MaxRetries=3
LogLevel=Info
ApiUrl=https://api.example.com
[ConnectionStrings]
DefaultConnection=Server=localhost;Database=Test;Integrated Security=True
读取 INI 文件:
var config = new ConfigurationBuilder()
.AddIniFile("appsettings.ini", optional: true, reloadOnChange: true)
.Build();
除了传统的app.config
,新配置系统也支持读取 XML 文件:
<configuration>
<AppSettings>
<MaxRetries>3MaxRetries>
<LogLevel>InfoLogLevel>
AppSettings>
<ConnectionStrings>
<DefaultConnection>Server=localhost;Database=Test;DefaultConnection>
ConnectionStrings>
configuration>
读取 XML 文件:
var config = new ConfigurationBuilder()
.AddXmlFile("appsettings.xml", optional: true, reloadOnChange: true)
.Build();
配置热重载允许应用在不重启的情况下读取更新后的配置:
// 启用热重载
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", reloadOnChange: true) // 启用热重载
.Build();
// 监控配置变化
var changeToken = config.GetReloadToken();
changeToken.RegisterChangeCallback(state =>
{
Console.WriteLine("配置已更新!");
// 重新获取配置
// ...
}, null);
在ASP.NET Core
中使用IOptionsSnapshot
或IOptionsMonitor
自动获取热重载的配置。
为避免将开发环境的敏感信息提交到代码库,可使用用户密钥(User Secrets):
dotnet user-secrets init
dotnet user-secrets set "Credentials:Password" "dev-password"
// 自动读取用户密钥(仅在开发环境生效)
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddUserSecrets<Program>() // 传入任意类型以确定项目
.Build();
string password = config["Credentials:Password"];
敏感信息(如密码、API 密钥)不应明文存储,可使用 DPAPI 或 Azure Key Vault 等进行加密。
使用 DataProtection 加密配置
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.DependencyInjection;
// 加密配置
var serviceCollection = new ServiceCollection();
serviceCollection.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"C:keys"))
.SetApplicationName("MyApp");
var services = serviceCollection.BuildServiceProvider();
var protector = services.GetDataProtectionProvider().CreateProtector("ConfigProtection");
// 加密
string plainText = "sensitive-password";
string encryptedText = protector.Protect(plainText);
// 解密
string decryptedText = protector.Unprotect(encryptedText);
Azure Key Vault
对于云部署,推荐使用 Azure Key Vault 存储敏感配置:
// 安装包:Install-Package Azure.Extensions.AspNetCore.Configuration.Secrets
var config = new ConfigurationBuilder()
.AddAzureKeyVault(new Uri("https://myvault.vault.azure.net/"),
new DefaultAzureCredential())
.Build();
应用在不同环境(开发、测试、生产)通常需要不同配置,.NET Core 提供了环境区分机制。
通过ASPNETCORE_ENVIRONMENT
(Web 应用)或DOTNET_ENVIRONMENT
(控制台应用)环境变量指定当前环境:
# 开发环境
set ASPNETCORE_ENVIRONMENT=Development
# 生产环境
set ASPNETCORE_ENVIRONMENT=Production
在 Docker 中设置:
ENV ASPNETCORE_ENVIRONMENT=Production
创建环境特定的配置文件,命名格式为appsettings.[Environment].json
:
appsettings.Development.json
:开发环境配置appsettings.Test.json
:测试环境配置appsettings.Production.json
:生产环境配置配置文件加载顺序:
appsettings.json
(基础配置)appsettings.[Environment].json
(环境特定配置,覆盖基础配置)// 加载环境特定配置
var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production";
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false)
.AddJsonFile($"appsettings.{env}.json", optional: true)
.Build();
ASP.NET Core
中配置多环境ASP.NET Core
自动处理多环境配置,可在Program.cs
中针对不同环境进行配置:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// 根据环境配置中间件
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage(); // 开发环境显示详细错误页
}
else
{
app.UseExceptionHandler("/Error"); // 生产环境使用自定义错误页
app.UseHsts(); // 生产环境启用HSTS
}
// 其他中间件配置
app.UseHttpsRedirection();
app.UseStaticFiles();
// ...
app.Run();
IOptions
而非直接访问IConfiguration
,提高可测试性Database
、Logging
、ExternalServices
等// 配置验证示例(使用DataAnnotations)
public class AppSettingsOptions : IValidatableObject
{
[Required]
public int MaxRetries { get; set; }
[Required]
[Url]
public string ApiUrl { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (MaxRetries < 0 || MaxRetries > 10)
{
yield return new ValidationResult(
"最大重试次数必须在0-10之间",
new[] { nameof(MaxRetries) });
}
}
}
// 在依赖注入中启用验证
services.AddOptions<AppSettingsOptions>()
.Bind(config.GetSection(AppSettingsOptions.AppSettings))
.ValidateDataAnnotations() // 启用DataAnnotations验证
.ValidateOnStart(); // 应用启动时验证
配置未更新:
IOptionsSnapshot
或IOptionsMonitor
)敏感信息泄露:
配置绑定失败:
IOptions.Value
时检查是否为null
多环境配置不生效:
ASPNETCORE_ENVIRONMENT
)C# 提供了从传统 XML 配置到现代多源配置系统的完整解决方案:
传统.NET Framework
:使用app.config
/web.config
和ConfigurationManager
,适合维护旧项目.NET Core/.NET 5+
:采用新配置系统,支持多种配置源、热重载和依赖注入,是新项目的首选IOptions
系列接口提供强类型配置访问,提高代码可维护性和可测试性选择合适的配置方式应根据项目类型(传统框架还是现代框架)、部署环境(本地还是云原生)、团队习惯等因素综合考虑。无论采用哪种方式,保持配置的清晰组织、敏感信息的安全保护以及配置的可扩展性都是关键原则。