How to update appsettings.json based on publish pr

2020-04-03 04:42发布

问题:

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!

回答1:

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



回答2:

...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.