Prisoner ZERO
Prisoner ZERO

Reputation: 14176

How to Manage AppSettings by Build Configuration name not Environment?

Currently, we use the BUILD CONFIGURATION from the Configuration Manager to drive web.config and app.config configuration-transformation in our builds.

For example
BUILD CONFIGURATION NAMES

We are in the midst of upgrading to .NET Core & a lot of examples show the use of Environment Variables to drive configuration-transformation in appsettings.json. But I can't seem to find examples that correctly transform the appsettings.json file using BUILD CONFIGURATION.

Q: Is it even possible to let the BUILD CONFIGURATION transform the appsettings.json file anymore?
Q: If so...how?

I am super not interested in going into 100+ servers & setting an environment variable in IIS.

static IHostBuilder CreateHostBuilder(string[] args)
{
    var builder = new HostBuilder()
                        .ConfigureAppConfiguration((hostingContext, config) =>
                        {
                            var env = hostingContext.HostingEnvironment; //<-- I dont want to do this

                            config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                                  .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
                        })
                        .UseServiceProviderFactory<ServiceRegistry>(new LamarServiceProviderFactory())
                        .ConfigureServices((hostContext, services) =>
                        {
                            var connectionString = hostContext.Configuration.GetConnectionString(JsonSettings.ConnectionStrings.WorkflowComponentDb);

                            services.AddLamar(new ContainerRegistry());
                            services.AddDbContext<IntegrationDbContext>((provider, options) => { options.UseSqlServer(connectionString); });
                            services.AddOptions();
                        })
                        .UseConsoleLifetime();
    return builder;
}

Upvotes: 2

Views: 1953

Answers (4)

Prisoner ZERO
Prisoner ZERO

Reputation: 14176

Okay, as it turns out some folks were VERY close...but here is the answer:

  1. You must apply "Copy Always" to all variations of the "appsettings.{BuildName}.json" files.
  2. Retrieve the current build-configuration (name) using the executing assembly
  3. Apply the concatenation as below

Why is this favorable? (to me)
I don't have to change my existing Azure DevOps pipelines.
I don't need to register ENVIRONMENTAL variables on machines.
I don't need to worry about "competing builds" on build servers.
I don't have to dedicate build servers to specific ENVIRONMENTAL variables.
I don't need to create "launch setting" files.

...all of which seem bloated & over-complicated (to me)

THAT SAID:
If you can see a reason why ENVIRONMENTAL variables are better (than this)...I would be interested in your thoughts. It just seems like "too many moving parts" (to me).

static IHostBuilder CreateHostBuilder(string[] args)
{
    var builder = new HostBuilder()
                        .ConfigureAppConfiguration((hostingContext, config) =>
                        {
                            var assemblyConfigurationAttribute = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyConfigurationAttribute>();
                            var buildConfiguration = assemblyConfigurationAttribute?.Configuration;

                            switch (buildConfiguration)
                            {
                                case "Development":
                                case "ModelOffice":
                                case "Production":
                                case "Release":
                                    config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                                          .AddJsonFile($"appsettings.{buildConfiguration}.json", optional: true, reloadOnChange: true);
                                    break;
                                default:
                                    config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
                                    break;
                            }
                        })
                        .UseServiceProviderFactory<ServiceRegistry>(new LamarServiceProviderFactory())
                        .ConfigureServices((hostContext, services) =>
                        {
                            var connectionString = hostContext.Configuration.GetConnectionString(JsonSettings.ConnectionStrings.WorkflowComponentDb);

                            services.AddLamar(new ContainerRegistry());
                            services.AddDbContext<IntegrationDbContext>((provider, options) => { options.UseSqlServer(connectionString); });
                        })
                        .UseConsoleLifetime();
    return builder;
}

Upvotes: 1

funatparties
funatparties

Reputation: 549

For local development, in the launchSettings.json file, you can create any configurations you like, and then launch them using VS by selecting one of them in the Start button dropdown list. This way the environment variables are read from this file behind the scenes when you run the application.

For production I asked how are you deploying the app, since if you have some automation scripts you can set the environment variable in those scripts, in the part where you run/release the app, something like

dotnet run --environment Production

Apparently there's also some possibility to set it in web.config file, this may be most useful for you but I have not used it myself.

Last thing I want to mention is that the runtime will read appsettings.json file plus appsettings.<YOUR_ASPNETCORE_ENVIRONMENT_VALUE>.json and will override any overlapping settings from appsettings.json file with those. This is done behind the scenes and you don't have to read those files manually in the app via code, like in some other answers in this post (you still need to add them manually into the project).

Upvotes: 1

sa-es-ir
sa-es-ir

Reputation: 5102

I think you need to create some appsetting.json based on your build names like:

  • appsetting.Debug.json
  • appsetting.Release.json
  • appsetting.Local.json
  • so on ...

So there are two ways to handle the settings:

  • 1- Old way
 config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
#if Local
.AddJsonFile("appsettings.Local.json", optional: false, reloadOnChange: true)
#elif ModelOffice
.AddJsonFile("appsettings.ModelOffice.json", optional: false, reloadOnChange: true)
//add another files
#endif
;
  • 2- Use the Configuration name and ASPNETCORE_ENVIRONMENT

First you need to create a configuration based on the build name like this:

enter image description here

And in the launchSetting.json file use this:

  "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "$(Configuration)"
      }

And finally in the program.cs

 config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: false, reloadOnChange: true);

Upvotes: 1

tmaj
tmaj

Reputation: 35135

One way would be to define a different compilation symbol for each configuration and use that to #if X set the environment name.

Please see Set the environment in code.

Upvotes: 1

Related Questions