How to update appsettings.json based on publish profile using .NET Core?
Asked Answered
H

3

15

I'm currently making the switch from .NET Framework to .NET Core. In the past, all of my application settings were in the Web.config file. When I added a new publish profile, I could right click and select 'Add Config Transform' which would generate a nested Web.{Profile}.config file under Web.config where I could set application settings that were specific to the respective profile.

Now, in .NET Core, I want to achieve the same effect using an appsettings.json file instead of Web.config file. How can I create an appsettings.{Profile}.json file which will be nested under my appsettings.json file and contain settings that are specific to my publish profile? Of course, I can create the file manually, but what is it that 'links' the settings so that they will override appsettings.json when the application is published? Is there a simple way to do this in Visual Studio like I described for my old .NET Framework projects? Or am I missing something?

Thanks!

Hiroko answered 16/11, 2018 at 1:58 Comment(0)
F
19

but what is it that 'links' the settings so that they will override appsettings.json when the application is published?

The appsettings are configured by WebHost in Program.cs

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>();

In the implementation of webhost.cs the framework adds the appsettings to the webhost:

config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
      .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

The second line is where it adds the environment specific appsettings. Within Visual Studio this environment variable is defined in the Project Settings -> Debug page and is called ASPNETCORE_ENVIRONMENT. By default it is set to Development so when you build and run within Visual Studio the appsettings.development.json file (if it exists) will be loaded and override any matching settings in the appsettings.json file.

When you publish your application you can override this value using an OS environment variable of the same name. There is an hierarchy of where .NET Core reads the values from and has a "last one wins " policy.

The hierarchy is currently:

  1. Files (appsettings.json, appsettings.{Environment}.json, where {Environment} is the app's current hosting environment)
  2. Azure Key Vault
  3. User secrets (Secret Manager) (in the Development environment only)
  4. Environment variables
  5. Command-line arguments

So when you publish your app you can override the environment on the host OS using an environment variable. When .NET Core starts your published app it will read that variables and load the appropriate appsettings.{environment}.json file. IF the value is not set, or no file exists for that environment, then the settings in appsettings.json will apply.

You can read more about the ASPNETCORE_ENVIROMENT setting here

Flatling answered 16/11, 2018 at 3:22 Comment(6)
This is wonderful, and I assume correct, but doesn't really answer the question of how to replace web.config transforms. What if my dev and multiple test environments all exist on the same machine? How can I have a unique OS level Environment Variable for each HOST? I would really like an actual transformation solution that is works on build (or publish) not run time.Ballata
.Net Core apps are build once run anywhere so web.config transforms are no longer recommended. See this answer for a good description. In your multiple host environment then you can use command-line arguments to override the {environment} value for that instance and allow you to use different settings for different instancesFlatling
The fact I can theoretically run my fancy new .NET Core app on any platform, is a nice marketing gimmick from Microsoft to keep up with the Jones', but in reality, most Microsoft developers know the platform they are going to deploy to and it is likely an IIS server. While I can appreciate transforms are no longer "recommended" I do need a continuous integration solution that is as easy as web.config transforms were.Ballata
If you are only targeting Windows then your best bet is to stick with .Net Framework as is designed purely for Windows and offers a larger Windows specific API surface. Microsoft have a page that helps you choose which framework to use. Although .Net Core is the “shiny new toy” it’s not always the best choice :-)Flatling
Agreed. Though I have found some nice advantages to moving to .NET Core, even on a pure Windows environment. We do lose some nice Windows specific API, as you say, but I have found it forces us instead to consider there are other platforms out there, and how to program in a more agnostic way. That and it seems there is always some Dev Manager who feels the need to be on the latest [greatest] regardless. :^)Ballata
Totally agree with you iGanja - its pretty pathetic that there's no standard workflow appsettings transform files natively. It seems like this functionality is pretty straight forward, could follow the same directive and path previous transforms did, and ultimately integrate with publish profiles in selecting the appropriate config for the publish. Come on microsoft!Fenestra
B
6

...and since my original comment, I have since come to find that web.config transforms are fully supported by VS 2017 and MS Build for .NET Core, once you realize the nesting and transform build commands do not need to be part of the project any longer. Do not use the "Add Config Transforms" command on your web.config any longer, unless you find a fix that doesn't corrupt your project file. Simply manually add transform versions of your web.config, and they will automatically nest and run on publish. Yea VS 2017!

The following, in your web.Release.config works very nicely to set your Environment Variable.

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <location>
    <system.webServer>
      <aspNetCore>
        <environmentVariables>
          <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" xdt:Locator="Match(name)" xdt:Transform="SetAttributes" />
        </environmentVariables>
      </aspNetCore>
    </system.webServer>
  </location>
</configuration>

Additionally, with .NET Core 2.2, you no longer need to add the additional appsettings transforms (switching off your Environment Variable,) to your Startup class. This default...

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

...takes care of the accepted answer's code automatically.

The bottom-line is, as an unapologetic Microsoft developer, I still want to assume my application will only be published to an IIS server, using MS Build and Web Deploy, and I would like the ability to configure my application through the application's own config; and I want to be able to do this on Build, not as a publish or post-publish command-line command. If Microsoft or someone creates a simple build plugin for Visual Studio that will transform my appsettings.json file, so I only publish what is necessary for the given environment, I will gladly use it, but I haven't found one, or had the time to write one, yet.

And just so I make sure to answer the OP's question directly: AppSettings can easily be transferred from web.config to appsettings.json, and probably should, as long as you understand ALL of the appsettings.json files are published, and determined at run-time, unlike a true transform solution where only the necessary files and settings are published, based on the requested profile. Using the web.config transform only to set the environment variable necessary to determine which appsettings.{env}.json file to use. Again, this whole discussion goes the way of the Dodo, if we can transform our apsettings.json file the same as our web.config, as the OP requested. I have a feeling it will come someday, if it hasn't already.

Yes, moving from a legacy .NET Framework to .NET Core can be a fun exercise. .NET Core is a huge step forward, but there are a few hurdles to get over; especially for those who have been on legacy since the start.

Ballata answered 26/4, 2019 at 16:44 Comment(2)
@Toolkit - possibly. There is a transformation plugin for VS that will transform any (other) xml based file like app.config. It is called Configuration Transform by Golan Avraham marketplace.visualstudio.com/…Ballata
Here is an interesting 2020 article from MS on using Web.config with Core 3.1: learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/…Maceio
E
0

Here's an ugly work-around:

In an Azure build pipeline, after building the ASP.NET core project, copy the appsettings.Production.json file to a separate folder in the artifact folder. In the release pipeline, use a 'Replace tokens' task to replace tokens in that json file with release variables. After deploying the app to IIS copy the 'transformed' appsettings.Production.json to the web site folder.

It works...

Egide answered 31/3, 2021 at 9:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.