.NET应用如何加载多个 appsettings.json 文件
在 .NET 应用中,通常使用 appsettings.json 文件存储应用的配置信息。对于有多个环境的项目,通常还会针对每个环境,再创建一个 appsettings.{Environment}.json 用于存储特定于每个环境的配置,比如 appsettings.Development.json、appsettings.Production.json 等。然后,可以在代码中,加载并合并 appsettings.json 和 appsettings.{Environment}.json。对于简单的值为字符串类型的配置,合并规则简单明了:直接覆盖即可。但是,如果配置项是复杂结构,比如嵌套的字典和数组,那么合并多个配置文件时,是什么规则呢?
简单地说:对于嵌套的字典,那么根据字典的键逐层进行覆盖或者增加;而数组其实是被当作字典对待的,数组的索引是键的一部分,然后按照字典的规则进行合并。
下面通过简单的代码进行演示。
代码示例
首先创建一个C#的 .NET 控制台程序,并且安装处理配置的包 Microsoft.Extensions.Configuration.Json。同时将 appsettings.json 和 appsettings.Development.json 文件添加到项目文件清单中。最终,csproj 文件的内容为:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup>
<ItemGroup> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.3" /> <Content Include="appsettings.json;appsettings.Development.json"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </Content> </ItemGroup>
</Project>程序代码文件 Program.cs 的内容为:
using Microsoft.Extensions.Configuration;
class Program{ static void Main() { var configuration = new ConfigurationBuilder() .SetBasePath(AppContext.BaseDirectory) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.Development.json", optional: false, reloadOnChange: true) .Build();
foreach (var item in configuration.AsEnumerable()) { Console.WriteLine($"{item.Key} -> {item.Value}"); } }}从代码中可以看出,其实每个配置项(即 item )都是键值对,其类型为 KeyValuePair<string, string?>。
appsettings.json 内容如下:
{ "Transforms": [ { "RequestHeaderOriginHost": "true" } ]}appsettings.Development.json 的内容如下:
{ "Transforms": [ { "PathRemovePrefix": "/prefix" }, { "RequestHeaderOriginHost": "false" } ]}运行结果
构建和运行应用,控制台输出为:
Transforms ->Transforms:1 ->Transforms:1:RequestHeaderOriginHost -> falseTransforms:0 ->Transforms:0:RequestHeaderOriginHost -> trueTransforms:0:PathRemovePrefix -> /prefix如果将其还原成 JSON 格式,那么就得到合并后的 JSON,其实为:
{ "Transforms": [ {"RequestHeaderOriginHost": "true", "PathRemovePrefix": "/prefix"}, {"RequestHeaderOriginHost": "false"} ]}这可能并不是期望的结果。
从控制台的输出,还可以看到:在迭代每个配置项时,对于值为数组的元素,并没有按照数组下标遍历。而是先输出第二个元素(即 Transforms:1 ),再输出第一个元素(即 Transforms:0)。