Manage different Appsettings files based on the Environment target

Working on a solution it is vital that you have the ability to differentiate configurations based on the solution’s “target” environment. The simplest example is that of DB connection strings: if you have different environments you will normally need different strings based on the DB hosted in the related env. In general, for ASP.NET Core projects (and not only) it is possible to manage as many settings as there are release environments, but it is not so trivial to find a way to make this in a dynamic and configurable way. In fact, I found a lot of documentation on how to play with environment variables [1] which however, in the target environment (a cloud solution), I cannot touch. After several hours of searching online for something which may help I landed on this solution which I will explain to you and which you can also partially find in this video.

Definition of release environments: first let’s define which environments my solution must cover to understand how many configuration file variants are needed. In my case there are 4:

  • Development: configuration used in Visual Studio 2022 when I’m developping and debugging
  • Stage: configuration used to test the solution in a ISS local machine
  • Sandbox: preprod environment in cloud
  • Live: final environment in cloud

For each of these environments I will need a dedicated appsettings file formatted in the following way: appsettings.{env}.json. To do this, just copy the appsettings file already present in the solution and rename it using the four names above. Always keep in mind that the first file to be read is appsettings (the generic one) which will then be overwritten by the one with the environment name. This means that anything that claims to be environment specific must end up in the file with the environment name itself.

Loading the correct settings: in the Program.cs we first load the generic appsettings file in which we create a configuration that we identify with Configuration where we will write the deployment target (one of the 4 values ‚Äč‚Äčabove). And based on that value we load the dedicated file.

var _conf = builder.Configuration.AddJsonFile("appsettings.json", optional: true, false).Build();
string _env = _conf.GetSection("Configuration").Value;
builder.Configuration.AddJsonFile($"appsettings.{_env}.json", optional: true, false);

var app = builder.Build();

This means that the environment target will be defined in the Appsettings.json file under the Configuration property.

Release only the environment files: as done above and substantially also shown in the video, all appsettings files will always be delivered in all environments and I don’t like this very much because it lends itself to errors if I don’t correctly modify the Configuration at the internal of the generic appsettings. To overcome this problem I generate 3 new configuration versions from the configuration manager: Live, Sandbox and Stage. At this point I open the project file in edit and add the following configuration which releases only the correct file based on the target I have chosen.

	<Choose>
		<When Condition="'$(Configuration)' == 'Live'">
			<ItemGroup>
				<None Include="appsettings.Live.json" CopyToOutputDirectory="Always" CopyToPublishDirectory="Always" />
				<None Include="appsettings.json" CopyToOutputDirectory="Never" CopyToPublishDirectory="Never" />
				<Content Remove="appsettings.*.json;appsettings.json" />
			</ItemGroup>
		</When>
		<When Condition="'$(Configuration)' == 'Sandbox'">
			<ItemGroup>
				<None Include="appsettings.Sandbox.json" CopyToOutputDirectory="Always" CopyToPublishDirectory="Always" />
				<None Include="appsettings.json" CopyToOutputDirectory="Never" CopyToPublishDirectory="Never" />
				<Content Remove="appsettings.*.json;appsettings.json" />
			</ItemGroup>
		</When>
		<When Condition="'$(Configuration)' == 'Stage'">
			<ItemGroup>
				<None Include="appsettings.Stage.json" CopyToOutputDirectory="Always" CopyToPublishDirectory="Always" />
				<None Include="appsettings.json" CopyToOutputDirectory="Never" CopyToPublishDirectory="Never" />
				<Content Remove="appsettings.*.json;appsettings.json" />
			</ItemGroup>
		</When>
		<Otherwise>
			<ItemGroup>
				<None Include="appsettings.Development.json" CopyToOutputDirectory="Always" CopyToPublishDirectory="Always" />
				<None Include="appsettings.json" CopyToOutputDirectory="Never" CopyToPublishDirectory="Never" />
				<Content Remove="appsettings.*.json;appsettings.json" />
			</ItemGroup>
		</Otherwise>
	</Choose>

In this way, before releasing in one of the environments, simply select the deployment type and only the relevant configuration files will be released.

[1] https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-8.0#evcp