C# 读取 appsettings.json 配置指南

本文档介绍了在 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.Configuration
  • Microsoft.Extensions.Configuration.Json
  • Microsoft.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 变为 0bool 变为 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#

      csharp 复制代码
      string rawValue = ConfigHelper.Configuration["MaxUsers"];
      if (int.TryParse(rawValue, out int safeMaxUsers)) {
          // 解析成功,使用 safeMaxUsers
      } else {
          // 解析失败,使用默认逻辑
      }
相关推荐
code_YuJun20 小时前
Spring ioc 完全注解
后端
kevinzeng20 小时前
反射的初步理解
后端·面试
下次一定x20 小时前
深度解析 Kratos 客户端服务发现与负载均衡:从 Dial 入口到 gRPC 全链路落地(上篇)
后端·go
kevinzeng20 小时前
Spring 核心知识点:EnvironmentAware 接口详解
后端
xyy12320 小时前
C# / ASP.NET Core 依赖注入 (DI) 核心知识点
后端
yuhaiqiang21 小时前
为什么我建议你不要只问一个AI?🤫偷偷学会“群发”,答案准到离谱!
人工智能·后端·ai编程
双向331 天前
AR 眼镜拯救社恐:我用 Kotlin 写了个拜年提词器
后端
吾日三省Java1 天前
Spring Cloud架构下的日志追踪:传统MDC vs 王炸SkyWalking
java·后端·架构
想打游戏的程序猿1 天前
服务端用AI写前端:隐患、困境与思考
后端