How to publish environment specific appsettings in .Net core app?

时间:2016-08-31 17:52:29

标签: asp.net-core .net-core asp.net-core-1.0 coreclr

I have 3 environment specific appsettings files in my .Net core application

enter image description here

in project.json I have setup publishOptions like this. ( based on suggestion here)

"publishOptions": {
    "include": [
      "wwwroot",      
      "appsettings.development.json",
      "appsettings.staging.json",
      "appsettings.production.json",
      "web.config"
    ]
  },

I have 3 corresponding startup classes that uses appropriate appsettings based on environment

var builder = new ConfigurationBuilder()
    .SetBasePath(env.ContentRootPath)
    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: false, reloadOnChange: true);

However when I publish the application then all 3 appsettings files end up in all environments. How do I publish environment specific appsetting file?

12 个答案:

答案 0 :(得分:4)

如果其他人想知道如何在多个环境中使用不同的应用程序设置,这里是一种可能的解决方案。

dotnet publish --configuration [Debug|Release]将把适当的appsettings.json文件复制到publish文件夹中,如果*.csproj具有这些文件的条件逻辑:

  • 首先在.pubxml发布配置文件(可以在Visual Studio的Properties-> PublishProfiles中找到)禁用默认情况下包含所有内容文件
<PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <EnableDefaultContentItems>false</EnableDefaultContentItems>
</PropertyGroup>
  • 然后指定条件Debug / Release逻辑
<Choose>
    <When Condition="'$(Configuration)' == 'Debug'">
      <ItemGroup>
        <None Include="appsettings.json" CopyToOutputDirectory="Always" CopyToPublishDirectory="Always" />
        <None Include="appsettings.prod.json" CopyToOutputDirectory="Never" CopyToPublishDirectory="Never" />
      </ItemGroup>
    </When>
    <When Condition="'$(Configuration)' == 'Release'">
      <ItemGroup>
        <None Include="appsettings.json" CopyToOutputDirectory="Never" CopyToPublishDirectory="Never" />
        <None Include="appsettings.prod.json" CopyToOutputDirectory="Always" CopyToPublishDirectory="Always" />
      </ItemGroup>
    </When>
</Choose>
  • 最后在Startup.cs内尝试加载两个文件
public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile($"appsettings.prod.json", optional: true, reloadOnChange: true)
        .AddJsonFile($"appsettings.json", optional: true, reloadOnChange: true)
        .AddEnvironmentVariables();

    Configuration = builder.Build();
}

我希望这个解决方案对您有所帮助。

答案 1 :(得分:3)

One possible way would be to run prepublish or postpublic scripts/commands, for example by running an gulp task executing dotnet publish-iis (alternatively use a task in prepublish section of scripts to copy the files to the before publishing.

Add this to your project.json:

"scripts": {
  "postpublish": [ "gulp cleanconfig", "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
}

You can also run a cmd or shell command here. But actually there shouldn't be any reasons why you would want to do this in the first place, just ship all 3 appconfig files, because on i.e. Azure App Service, you can switch the mode depending on the environment variables which is regulated via the Azure Portal and when publishing, the staging and production slots will be just swapped, but the environmental variables stay.

You shouldn't store secrets within the appsettings.json though (which I assume you doe and the reason you want to remove the files). Instead, use "user secrets" for development and environmental variables to set connection strings etc. for production. Works like a charm, especially with Azure App Services and docker containers.

答案 2 :(得分:2)

在VS2017中添加多个环境

步骤  右键单击项目 - &gt;添加 - &gt; NewItem - 选择json文件 - 将文件名写为'appsettings.staging.json'或'appsettings.production.json'

Add appsettings.staging.json file

Output Looks like

答案 3 :(得分:1)

您需要实际添加环境变量according the official tutorial

var builder = new ConfigurationBuilder()
    .SetBasePath(env.ContentRootPath)
    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: false, reloadOnChange: true)
    // do not forget to add environment variables to your config!
    .AddEnvironmentVariables();

答案 4 :(得分:1)

我有同样的问题,因为由于多个站点使用相同的代码库,因此需要在不同的生产配置文件之间切换。

最后,我为每个客户端/站点创建了一个powershell脚本。该脚本在生产配置文件上复制特定于客户端的配置文件,然后运行发布。我实际上是对appSettings.json文件和environment.ts文件都这样做。该脚本看起来像这样:

Remove-Item –path ClientApp\src\environments\environment.prod.ts
Remove-Item –path appsettings.production.json
Write-Output "--> config files removed"
Copy-Item -path ClientApp\src\environments\environment.CLIENT-SITE-NAME.ts ClientApp\src\environments\environment.prod.ts
Copy-Item -path appsettings.CLIENT-SITE-NAME.json appsettings.production.json
Write-Output "--> config files copied"
dotnet build MYPROJ.csproj -c Release /p:DeployOnBuild=true /p:PublishProfile=CLIENT-SITE-NAME 
Write-Output "--> built & published"
Remove-Item –path ClientApp\src\environments\environment.prod.ts
Remove-Item –path appsettings.production.json
Write-Output "Finished"

在我每个客户站点的.pubxml文件中,我都排除了所有非生产appsettings的发布,例如:

<ItemGroup>
  <Content Update="appsettings.json" CopyToPublishDirectory="Never" />
  <Content Update="appsettings.site1.json" CopyToPublishDirectory="Never" />
  <Content Update="appsettings.site2.json" CopyToPublishDirectory="Never" />
  <Content Update="appsettings.development.json" CopyToPublishDirectory="Never" />
</ItemGroup>

最后,我删除了生产文件,以确保我不会使用“发布”向导将它们意外地部署到错误的站点。

(我将密码存储在pubxml文件中,但您可以将其作为参数包含在脚本中)

答案 5 :(得分:1)

对于我来说,我有几个适用于多个实时环境的appSettings文件,例如appSettings.Env1Live.json,appSettings.Env2Live.json等。

我浏览了文章https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/visual-studio-publish-profiles?view=aspnetcore-3.1,并在每个环境的相应发布(pubxml)配置文件中添加了以下语句。

例如为PublishToEnvironment1.pubxml添加的:

<ItemGroup>
<Content Update="appsettings.*Live.json" CopyToPublishDirectory="Never" />
<Content Update="appsettings.Development.json" CopyToPublishDirectory="Never" />
<Content Update="appsettings.Env1Live.json" CopyToPublishDirectory="PreserveNewest" /></ItemGroup>

因此,在已发布的文件夹中,我只有两个必要的文件,其他appSettings。* Live.json没有发布。

appsettings.json

appsettings.Env1Live.json

答案 6 :(得分:0)

老实说,我认为这不是构建管道的正确任务。此外,dotnet cli的发布功能非常有限。转到Tseng向您展示的外部工具。部署是另一个具有自己的复杂性而不是构建的域。

除了使用外部工具之外,dotnet cli还没有一种构建方式!

答案 7 :(得分:0)

到目前为止,我发现的最简单的方法是部署所有配置文件,然后在部署完成后删除额外的文件。 只需在部署shell或批处理脚本的末尾添加一些额外的行。

答案 8 :(得分:0)

您可以使用MSBuild条件在编译输出(或发布的输出)中选择性地包含文件。

<ItemGroup Condition="'$(Configuration)'=='Release'">
  <Content Remove="appsettings.Development.json;appsettings.Staging.json" />
  <None Include="appsettings.Development.json;appsettings.Staging.json" />
</ItemGroup>

当编译目标配置为Release时,以上内容将忽略Development and Staging appsettings.json文件变体。

答案 9 :(得分:0)

我通过以下nuget软件包解决了这个问题:https://github.com/Microsoft/slow-cheetah/blob/master/doc/transforming_files.md

它非常容易安装并使用有效解决方案配置中的所有配置(在我的情况下-我为测试部署添加了新的“测试”配置)。

此后,您可以在VS中安装此扩展程序:https://marketplace.visualstudio.com/items?itemName=vscps.SlowCheetah-XMLTransforms

现在,您可以通过此工具在VS中为.xml或.json应用程序配置设置创建新的配置子文件(如手册中所述)。例如,我有Debug,Test,Release文件(appsettings.Debug.json等)

下一步-为每种配置设置发布配置文件,发布后,只有一个文件具有所有必要的转换。

在.net核心Web应用程序中,转换的工作方式类似于经典的.json环境转换。

答案 10 :(得分:0)

最近,我还必须为此找到一种解决方案,我通过在wait文件中添加了一些设置并在.csproj中进行了较小的更改来实现了它。

Program.cs

为了稍微解释一下,我为每种配置添加了一个<Project Sdk="Microsoft.NET.Sdk.Web"> <!-- ... --> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'"> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <DefineConstants>DEBUG;TRACE</DefineConstants> <EnvironmentName>Development</EnvironmentName> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'"> <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <EnvironmentName>Production</EnvironmentName> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Stage|AnyCPU'"> <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <EnvironmentName>Staging</EnvironmentName> </PropertyGroup> <ItemGroup> <Content Remove="appsettings.json" /> <Content Remove="appsettings.*.json" /> </ItemGroup> <ItemGroup> <Content Include="appsettings.json" CopyToOutputDirectory="PreserveNewest" /> <Content Include="appsettings.*.json" Exclude="appsettings.$(EnvironmentName).json" DependentUpon="appsettings.json" CopyToOutputDirectory="Never" /> <Content Include="appsettings.$(EnvironmentName).json" DependentUpon="appsettings.json" CopyToOutputDirectory="PreserveNewest" /> </ItemGroup> <Target Name="RenameAppsettings" AfterTargets="Publish"> <Move SourceFiles="$(OutputPath)\publish\appsettings.$(EnvironmentName).json" DestinationFiles="$(OutputPath)\publish\appsettings.overrides.json" /> </Target> </Project> 元素,以便可以在构建过程中使用它。我正在使用<EnvironmentName>(即appsettings.{EnvironmentName}.json)作为“替代”文件,因此在构建过程中只是让它重命名了必要的JSON文件。例如,当您运行appsettings.Staging.json时,它将把dotnet publish -c Stage文件发布到发布文件夹中,并将其重命名为appsettings.Staging.json。在您的appsettings.overrides.json中,您还只需要包含Program.cs文件:

appsettings.overrides.json

希望对您有帮助!

  

旁注:我包括 .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.overrides.json", optional: true, reloadOnChange: true) 并将其设置为appsettings.*.json,以便在开发时它们仍显示在Visual Studio中。否则,如果只希望在VS中显示当前环境的CopyToOutputDirectory="Never"文件,只需从appsettings文件中删除该行即可。

答案 11 :(得分:0)

        Consider you have multiple appsettings: dev,pre,prod. 
    You can have below configuration in your web project file.

         <!-- This configuration is done for dotnet publish command.
     It will make sure only environment specific files will be copied -->
          <ItemGroup Condition=" '$(EnvironmentName)' == 'Dev'">
            <Content Remove="appsettings.Prod.json" />
            <Content Remove="appsettings.Pre.json" />
          </ItemGroup>
          <ItemGroup Condition=" '$(EnvironmentName)' == 'Pre'">
            <Content Remove="appsettings.Prod.json" />
            <Content Remove="appsettings.Dev.json" />
            <Content Remove="appsettings.Development.json" />
          </ItemGroup>
          <ItemGroup Condition=" '$(**EnvironmentName**)' == 'Prod'">
            <Content Remove="appsettings.Pre.json" />
            <Content Remove="appsettings.Dev.json" />
            <Content Remove="appsettings.Development.json" />
          </ItemGroup>

        This confguration will help during publish. 
    It will not copy the appsettings which is not required for that environment.

        EnvironmentName (part of  <ItemGroup Condition=" '$(**EnvironmentName**)' == 'Prod'">) 
highlighted above should be passed as parameter in below command.

        dotnet publish -o ../../published/20191118A -c release /p:EnvironmentName=Development