本文档介绍了在 C# 项目中读取 appsettings.json 文件的常用方法,涵盖了现代 .NET 的依赖注入(DI)模式 以及适用于非 DI 环境的静态读取模式,并详细说明了不同数据类型的读取方式及常见踩坑点。
示例配置文件准备
在开始之前,在项目根目录创建一个 appsettings.json 文件,内容如下:
JSON
{
"AppName": "MyAwesomeApp",
"MaxUsers": 100,
"SupportedLanguages": [ "zh-CN", "en-US", "ja-JP" ],
"Database": {
"Host": "127.0.0.1",
"Port": 3306
}
}
🔴 极其重要的第一步:
在 Visual Studio 中,右键点击
appsettings.json-> 属性 -> 将 "复制到输出目录" (Copy to Output Directory) 设置为 "如果较新则复制" (Copy if newer) 。否则程序运行时会报找不到文件的错误!
模式一:依赖注入模式(推荐)
适用于 ASP.NET Core、Worker Service 等自带依赖注入容器的现代 .NET 项目。推荐使用强类型绑定(Options Pattern)。
1. 定义映射类
C#
public class DatabaseOptions
{
public string Host { get; set; }
public int Port { get; set; }
}
2. 注册配置 (Program.cs)
C#
var builder = WebApplication.CreateBuilder(args);
// 将 JSON 中的 "Database" 节点绑定到 DatabaseOptions 类
builder.Services.Configure<DatabaseOptions>(builder.Configuration.GetSection("Database"));
3. 在服务中注入并使用
C#
public class MyService
{
private readonly DatabaseOptions _dbOptions;
// 使用 IOptions<T> 注入
public MyService(IOptions<DatabaseOptions> options)
{
_dbOptions = options.Value;
}
public void Connect()
{
Console.WriteLine($"Connecting to {_dbOptions.Host}:{_dbOptions.Port}");
}
}
模式二:静态工具类模式(随时随地读取)
适用于控制台应用、WinForms/WPF,或者你想在任意静态方法中直接读取配置的场景。
前置准备: 通过 NuGet 安装以下包:
Microsoft.Extensions.ConfigurationMicrosoft.Extensions.Configuration.JsonMicrosoft.Extensions.Configuration.Binder
1. 创建静态配置助手类
使用静态构造函数确保配置只被加载一次:
C#
using Microsoft.Extensions.Configuration;
using System.IO;
public static class ConfigHelper
{
public static IConfiguration Configuration { get; }
static ConfigHelper()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
Configuration = builder.Build();
}
}
2. 按数据类型读取示例
以下代码演示了如何使用 ConfigHelper 读取不同类别的数据:
C#
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Configuration;
public class ConfigDemo
{
public static void Run()
{
// ----------------------------------------------------
// 1. 读取基本类型 (String, Int, Bool 等)
// 使用 GetValue<T> 可以在找不到配置时提供一个 fallback (默认值)
// ----------------------------------------------------
string appName = ConfigHelper.Configuration.GetValue<string>("AppName", "DefaultApp");
int maxUsers = ConfigHelper.Configuration.GetValue<int>("MaxUsers", 50);
Console.WriteLine($"App: {appName}, Max Users: {maxUsers}");
// ----------------------------------------------------
// 2. 读取列表 (List / Array)
// 需先 GetSection() 获取节点,再 Get<T>() 绑定
// ----------------------------------------------------
var languages = ConfigHelper.Configuration.GetSection("SupportedLanguages").Get<List<string>>();
if (languages != null)
{
Console.WriteLine("Languages: " + string.Join(", ", languages));
}
// ----------------------------------------------------
// 3. 读取对象 (Object)
// 同样先获取节点,再绑定到 C# 实体类
// ----------------------------------------------------
var dbConfig = ConfigHelper.Configuration.GetSection("Database").Get<DatabaseOptions>();
if (dbConfig != null)
{
Console.WriteLine($"DB Port: {dbConfig.Port}");
}
}
}
⚠️ 常见异常与排错指南 (Troubleshooting)
在读取配置文件时,经常会遇到以下两种边缘情况,请务必在代码中做好防御性编程:
1. 键不存在或值为空 (Null)
-
现象: 不会报错抛出异常。
-
表现:
- 使用
GetValue<T>()时,如果没有提供默认值,会返回类型T的默认值(如int变为0,bool变为false)。 - 使用
.Get<List<T>>()或.Get<Object>()时,如果节点不存在,会返回null。
- 使用
-
应对方案: 对于对象和列表,使用前必须进行判空校验 (
if (obj != null)) ,或者在 C# 类定义时初始化为空列表(例如public List<string> Langs { get; set; } = new();)。
2. 数据类型不匹配
-
现象: 会抛出
System.InvalidOperationException异常。 -
表现: 比如 JSON 中写的是
"MaxUsers": "一百",但你试图用GetValue<int>("MaxUsers")读取。底层转换器无法将 "一百" 解析为整型,程序将崩溃。 -
应对方案: * 严格规范 JSON 的数据类型(数字不要加双引号,保持为纯数字)。
-
对于高度不可信的外部配置,建议先读取为
string,然后使用int.TryParse()进行安全转换:C#
csharpstring rawValue = ConfigHelper.Configuration["MaxUsers"]; if (int.TryParse(rawValue, out int safeMaxUsers)) { // 解析成功,使用 safeMaxUsers } else { // 解析失败,使用默认逻辑 }
-