Как публиковать специальные приложения в среде .Net?

В моем основном приложении .Net есть 3 файла appsettings конкретной среды

enter image description here

в project.json меня есть настройка publishOptions как это. (на основании предложения здесь)

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

У меня есть 3 соответствующих класса запуска, которые используют соответствующие appsettings зависимости от среды

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

Однако когда я публикую приложение, все 3 файла appsettings окажутся во всех средах. Как опубликовать файл настроек приложения для конкретной среды?

Ответ 1

Если кто-то еще задается вопросом, как использовать разные наборы приложений для нескольких сред, здесь возможное решение.

dotnet publish --configuration [Debug|Release] скопирует соответствующий файл appsettings.json в папку публикации, если *.csproj имеет условную логику для этих файлов:

  • Сначала в .pubxml профиля публикации .pubxml (его можно найти в PublishProfiles PropertiesPublishProfiles в Visual Studio) отключите включение всех файлов содержимого по умолчанию.
<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();
}

Я надеюсь, что это решение было полезным.

Ответ 2

Одним из возможных способов было бы запустить подготовительные или пост-публичные скрипты/команды, например, запустив задачу gulp, выполняющую dotnet publish-iis (альтернативно, используя задачу в разделе prepublish scripts, чтобы скопировать файлы на перед публикацией.

Добавьте это в свой проект. json:

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

Вы также можете запустить команду cmd или shell. Но на самом деле не должно быть никаких причин, по которым вы хотели бы сделать это в первую очередь, просто отправляйте все 3 файла appconfig, потому что, например, Azure App Service, вы можете переключать режим в зависимости от переменных среды, которые регулируются через Azure Portal, и при публикации, промежуточные и производственные слоты будут просто заменены, но остаются переменными окружающей среды.

Вы не должны хранить секреты в appsettings.json, хотя (я предполагаю, что вы делаете и почему хотите удалить файлы). Вместо этого используйте "секреты пользователя" для разработки и переменных среды для установки строк подключения и т.д. Для производства. Работает как шарм, особенно с Azure App Services и контейнерами докеров.

Ответ 4

Недавно мне также пришлось найти решение для этого, и я достиг этого, добавив некоторые настройки в файл .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="$(PublishDir)\appsettings.$(EnvironmentName).json" DestinationFiles="$(PublishDir)\appsettings.overrides.json" />
    </Target>
</Project>

Чтобы объяснить это немного, я добавил элемент <EnvironmentName> для каждой конфигурации, чтобы его можно было использовать в процессе сборки. Я использую appsettings.{EnvironmentName}.json (т.е. appsettings.Staging.json) просто как файл переопределения, поэтому я просто переименую нужный JSON файл в процессе сборки. Например, когда вы запускаете dotnet publish -c Stage, он публикует файл appsettings.Staging.json в папку publish и переименовывает его в 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 и устанавливаю для него CopyToOutputDirectory="Never" чтобы они все еще CopyToOutputDirectory="Never" в Visual Studio при разработке. В противном случае, если вы хотите, чтобы текущий файл appsettings среды отображался в VS, просто удалите эту строку из файла csproj.

Ответ 5

Вам нужно фактически добавить переменные среды, согласно официальному учебнику:

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();

Ответ 6

Честно говоря, я считаю, что это не правильная задача для конвейера сборки. Также функции публикации dotnet cli очень ограничены. Идите к внешним инструментам, как показал вам Цзэн. Развертывание - это еще один домен с собственным набором сложностей, чем создание.

В dotnet cli нет встроенного метода вне использования внешних инструментов!

Ответ 7

Самый простой способ, который я нашел до сих пор, - развернуть все файлы конфигурации, а затем удалить дополнительные файлы после завершения развертывания. Просто добавьте несколько дополнительных строк в конец оболочки развертывания или пакет script.

Ответ 8

Вы можете использовать условия MSBuild для необязательного включения файлов в выходные данные компиляции (или опубликованные выходные данные).

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

Вышеприведенное игнорирует варианты файла Development and Staging appsettings.json, когда целевой конфигурацией компиляции является Release.

Ответ 9

Я решил этот вопрос с помощью этого пакета Nuget: https://github.com/Microsoft/slow-cheetah/blob/master/doc/transforming_files.md

Это так просто для установки и использования всех конфигураций в конфигурации активного решения (в моем случае - я добавил новую "тестовую" конфигурацию для тестового развертывания).

После этого вы можете установить это расширение в VS: https://marketplace.visualstudio.com/items?itemName=vscps.SlowCheetah-XMLTransforms.

Только сейчас вы можете создать новые конфигурационные подфайлы для параметров конфигурации приложения .xml или .json в VS этим инструментом (как в руководстве). Например, у меня есть файлы Debug, Test, Release (appsettings.Debug.json и т.д.)

Следующий шаг - настройка профилей публикации для каждой конфигурации, и после публикации у вас будет только один файл со всеми необходимыми преобразованиями.

Преобразования работают как классическая трансформация среды .json в основных веб-приложениях .net.