.NET Core 3.1发布时如何合并appsettings.{env}.json到appsettings.json?
是否可行?
当然可行,我们可以通过集成发布流程的自定义构建任务或独立工具实现这个需求,下面是两种实用方案:
方案一:MSBuild自定义目标(推荐,无缝集成发布流程)
.NET Core的发布基于MSBuild,我们可以在项目文件中添加自定义目标,在发布阶段自动执行配置合并,并排除多余的环境配置文件。
步骤1:编写配置合并脚本
在项目根目录创建MergeConfig.csx脚本,实现JSON配置的合并逻辑(支持嵌套节点覆盖):
using System; using System.IO; using System.Text.Json; using System.Collections.Generic; class Program { static void Main(string[] args) { if (args.Length != 3) { Console.WriteLine("参数格式:MergeConfig.csx <基础配置路径> <环境配置路径> <输出路径>"); return; } var basePath = args[0]; var envPath = args[1]; var outputPath = args[2]; // 读取配置文件 var baseDoc = JsonDocument.Parse(File.ReadAllText(basePath)); var envDoc = JsonDocument.Parse(File.ReadAllText(envPath)); // 递归合并节点 var mergedRoot = MergeJsonElements(baseDoc.RootElement, envDoc.RootElement); // 写入最终配置 var options = new JsonSerializerOptions { WriteIndented = true }; File.WriteAllText(outputPath, JsonSerializer.Serialize(mergedRoot, options)); Console.WriteLine($"配置合并完成:{outputPath}"); } static JsonElement MergeJsonElements(JsonElement baseElem, JsonElement envElem) { if (baseElem.ValueKind != JsonValueKind.Object || envElem.ValueKind != JsonValueKind.Object) { return envElem.ValueKind != JsonValueKind.Undefined ? envElem : baseElem; } var mergedDict = new Dictionary<string, JsonElement>(); // 先添加基础配置所有节点 foreach (var prop in baseElem.EnumerateObject()) { mergedDict[prop.Name] = prop.Value; } // 用环境配置覆盖或添加节点 foreach (var prop in envElem.EnumerateObject()) { if (mergedDict.ContainsKey(prop.Name)) { mergedDict[prop.Name] = MergeJsonElements(mergedDict[prop.Name], prop.Value); } else { mergedDict[prop.Name] = prop.Value; } } using var stream = new MemoryStream(); using var writer = new Utf8JsonWriter(stream); writer.WriteStartObject(); foreach (var kvp in mergedDict) { writer.WritePropertyName(kvp.Key); kvp.Value.WriteTo(writer); } writer.WriteEndObject(); writer.Flush(); stream.Seek(0, SeekOrigin.Begin); return JsonDocument.Parse(stream).RootElement; } }
步骤2:修改项目文件集成发布流程
在项目的.csproj文件中添加自定义MSBuild目标,指定发布前执行合并,并排除环境配置文件:
<Project Sdk="Microsoft.NET.Sdk.Web"> <!-- 原有项目配置 --> <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> <!-- 默认目标环境,发布时可通过参数覆盖 --> <TargetEnv>Development</TargetEnv> </PropertyGroup> <!-- 自定义合并配置目标 --> <Target Name="MergeAppSettings" BeforeTargets="Publish"> <!-- 校验环境配置文件存在 --> <Error Condition="!Exists('$(ProjectDir)appsettings.$(TargetEnv).json')" Text="未找到环境配置文件:appsettings.$(TargetEnv).json" /> <!-- 执行合并脚本 --> <Exec Command="dotnet script $(ProjectDir)MergeConfig.csx $(ProjectDir)appsettings.json $(ProjectDir)appsettings.$(TargetEnv).json $(PublishDir)appsettings.json" /> <!-- 排除所有环境配置文件,不复制到发布目录 --> <ItemGroup> <Content Remove="appsettings.*.json" /> <None Include="appsettings.*.json" /> </ItemGroup> </Target> </Project>
步骤3:发布时指定环境
通过/p:TargetEnv参数指定目标环境,执行发布:
dotnet publish -c Release /p:TargetEnv=Production
发布完成后,输出目录只会存在合并后的appsettings.json。
方案二:独立控制台工具(适合复杂逻辑场景)
如果合并逻辑需要更复杂的处理(比如加密、多环境切换),可以编写独立的控制台工具:
- 创建.NET Core 3.1控制台项目,将上面的合并逻辑迁移进去;
- 将工具发布为可执行文件,放在项目目录或全局路径;
- 在
.csproj中添加Exec任务调用工具,或在发布脚本中手动执行。
运行时注意事项
因为最终只有单个appsettings.json,需要修改Program.cs清除默认的多环境配置加载逻辑:
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((hostingContext, config) => { // 清除默认配置源,只加载合并后的配置文件 config.Sources.Clear(); config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); // 保留命令行等其他必要配置源 config.AddCommandLine(args); }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
内容的提问来源于stack exchange,提问作者Behrooz
相关产品推荐
相关产品推荐

