App.Config Преобразование для проектов, которые не являются веб-проектами в Visual Studio?
Для веб-приложения Visual Studio 2010 у нас есть функции преобразования конфигурации, с помощью которых мы можем поддерживать несколько файлов конфигурации для разных сред. Но та же функция недоступна для файлов App.Config для служб Windows/WinForms или консольного приложения.
Здесь предлагается обходной путь, предложенный здесь: Применение магии XDT к App.Config.
Однако это не просто и требует ряда шагов. Есть ли более простой способ добиться того же для файлов app.config?
17 ответов
Теперь это работает с надстройкой Visual Studio, описанной в этой статье: SlowCheetah - Синтаксис преобразования Web.config теперь обобщен для любого файла конфигурации XML.
Вы можете щелкнуть правой кнопкой мыши на своем файле web.config и нажать "Добавить преобразования конфигурации". Когда вы сделаете это, вы получите web.debug.config и web.release.config. Вы можете создать web.whwhat.config, если хотите, если имя совпадает с профилем конфигурации. Эти файлы - просто изменения, которые вы хотите внести, а не полная копия вашего web.config.
Вы можете подумать, что захотите использовать XSLT для преобразования web.config, но, хотя они кажутся интуитивно правильными, на самом деле они очень многословны.
Вот два преобразования, одно с использованием XSLT, а другое с использованием синтаксиса / пространства имен преобразования документов XML. Как и во всех вещах, в XSLT есть несколько способов сделать это, но вы поймете общую идею. XSLT - это обобщенный язык преобразования деревьев, в то время как этот вариант развертывания оптимизирован для определенного подмножества общих сценариев. Но самое интересное в том, что каждое XDT-преобразование представляет собой плагин.NET, поэтому вы можете создавать свои собственные.
<?xml version="1.0" ?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="/configuration/appSettings"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> <xsl:element name="add"> <xsl:attribute name="key">NewSetting</xsl:attribute> <xsl:attribute name="value">New Setting Value</xsl:attribute> </xsl:element> </xsl:copy> </xsl:template> </xsl:stylesheet>
Или то же самое с помощью преобразования развертывания:
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <appSettings> <add name="NewSetting" value="New Setting Value" xdt:Transform="Insert"/> </appSettings> </configuration>
Я попробовал несколько решений, и вот самое простое, которое я лично нашел.
Dan указал в комментариях, что оригинальный пост принадлежит Олегу Сычу - спасибо, Олег!
Вот инструкции:
1. Добавьте файл XML для каждой конфигурации в проект.
Как правило, у вас будет Debug
а также Release
конфигурации, так что назовите ваши файлы App.Debug.config
а также App.Release.config
, В моем проекте я создал конфигурацию для каждого типа среды, поэтому вы можете поэкспериментировать с этим.
2. Выгрузите проект и откройте файл.csproj для редактирования.
Visual Studio позволяет редактировать файлы .csproj прямо в редакторе - сначала нужно просто выгрузить проект. Затем щелкните по нему правой кнопкой мыши и выберите " Изменить
3. Привязать файлы конфигурации App. *. К основному файлу App.config.
Найдите раздел файла проекта, который содержит все App.config
а также App.*.config
Рекомендации. Вы заметите, что их действия по сборке установлены на None
:
<None Include="App.config" />
<None Include="App.Debug.config" />
<None Include="App.Release.config" />
Во-первых, установите действие сборки для всех Content
,
Затем сделайте все зависящие от конфигурации файлы зависимыми от основного App.config
Visual Studio группирует их так же, как это делает дизайнер и файлы с выделенным кодом.
Замените XML выше на приведенный ниже:
<Content Include="App.config" />
<Content Include="App.Debug.config" >
<DependentUpon>App.config</DependentUpon>
</Content>
<Content Include="App.Release.config" >
<DependentUpon>App.config</DependentUpon>
</Content>
4. Активируйте преобразования магии
В конце файла после
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
и до финала
</Project>
вставьте следующий XML:
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="CoreCompile" Condition="exists('app.$(Configuration).config')">
<!-- Generate transformed app config in the intermediate directory -->
<TransformXml Source="app.config" Destination="$(IntermediateOutputPath)$(TargetFileName).config" Transform="app.$(Configuration).config" />
<!-- Force build process to use the transformed configuration file from now on. -->
<ItemGroup>
<AppConfigWithTargetPath Remove="app.config" />
<AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
<TargetPath>$(TargetFileName).config</TargetPath>
</AppConfigWithTargetPath>
</ItemGroup>
</Target>
Теперь вы можете перезагрузить проект, собрать его и наслаждаться App.config
преобразования!
FYI
Убедитесь, что ваш App.*.config
файлы имеют правильную настройку, как это:
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--magic transformations here-->
</configuration>
Другое решение, которое я нашел, это НЕ использовать преобразования, а просто иметь отдельный файл конфигурации, например, app.Release.config. Затем добавьте эту строку в ваш файл csproj.
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<AppConfig>App.Release.config</AppConfig>
</PropertyGroup>
Это не только сгенерирует правильный файл myprogram.exe.config, но если вы используете проект установки и развертывания в Visual Studio для создания MSI, это заставит проект развертывания использовать правильный файл конфигурации при упаковке.
Вдохновленный Олегом и другими в этом вопросе, я предпринял решение /questions/21876244/appconfig-preobrazovanie-dlya-proektov-kotoryie-ne-yavlyayutsya-veb-proektami-v-visual-studio/21876262#21876262 на шаг, чтобы включить следующее.
- Работает с ClickOnce
- Работает с проектами установки и развертывания в VS 2010
- Работает с VS2010, 2013, 2015 (не тестировал 2012, хотя должен работать).
- Работает с Team Build. (Вы должны установить либо A) Visual Studio, либо B) Microsoft.Web.Publishing.targets и Microsoft.Web.Publishing.Tasks.dll)
Это решение работает путем выполнения преобразования app.config до того, как на app.config впервые будет сделана ссылка в процессе MSBuild. Он использует внешний файл целей для более удобного управления несколькими проектами.
Инструкции:
Аналогичные шаги для другого решения. Я процитировал то, что остается тем же самым и включил это для полноты и более простого сравнения.
0. Добавьте новый файл в ваш проект с именем AppConfigTransformation.targets
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Transform the app config per project configuration.-->
<PropertyGroup>
<!-- This ensures compatibility across multiple versions of Visual Studio when using a solution file.
However, when using MSBuild directly you may need to override this property to 11.0 or 12.0
accordingly as part of the MSBuild script, ie /p:VisualStudioVersion=11.0;
See http://blogs.msdn.com/b/webdev/archive/2012/08/22/visual-studio-project-compatability-and-visualstudioversion.aspx -->
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.targets" />
<Target Name="SetTransformAppConfigDestination" BeforeTargets="PrepareForBuild"
Condition="exists('app.$(Configuration).config')">
<PropertyGroup>
<!-- Force build process to use the transformed configuration file from now on. -->
<AppConfig>$(IntermediateOutputPath)$(TargetFileName).config</AppConfig>
</PropertyGroup>
<Message Text="AppConfig transformation destination: = $(AppConfig)" />
</Target>
<!-- Transform the app.config after the prepare for build completes. -->
<Target Name="TransformAppConfig" AfterTargets="PrepareForBuild" Condition="exists('app.$(Configuration).config')">
<!-- Generate transformed app config in the intermediate directory -->
<TransformXml Source="app.config" Destination="$(AppConfig)" Transform="app.$(Configuration).config" />
</Target>
</Project>
1. Добавьте файл XML для каждой конфигурации в проект.
Обычно у вас есть конфигурации Debug и Release, поэтому назовите ваши файлы App.Debug.config и App.Release.config. В моем проекте я создал конфигурацию для каждого вида среды, так что вы можете поэкспериментировать с этим.
2. Выгрузите проект и откройте файл.csproj для редактирования.
Visual Studio позволяет редактировать.csproj прямо в редакторе - вам просто нужно сначала выгрузить проект. Затем щелкните по нему правой кнопкой мыши и выберите "Редактировать.csproj".
3. Привязать файлы конфигурации App. *. К основному файлу App.config.
Найдите раздел файла проекта, содержащий все ссылки на App.config и App. *. Config, и замените его следующим образом. Вы заметите, что мы используем None вместо Content.
<ItemGroup>
<None Include="app.config"/>
<None Include="app.Production.config">
<DependentUpon>app.config</DependentUpon>
</None>
<None Include="app.QA.config">
<DependentUpon>app.config</DependentUpon>
</None>
<None Include="app.Development.config">
<DependentUpon>app.config</DependentUpon>
</None>
</ItemGroup>
4. Активируйте преобразования магии
В конце файла после
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
и до финала
</Project>
вставьте следующий XML:
<Import Project="AppConfigTransformation.targets" />
Готово!
По моему опыту, вещи, которые мне нужно сделать для конкретной среды, это такие вещи, как строки подключения, настройки приложений и часто игнорируемые настройки. Система конфигурации позволяет указывать эти вещи в отдельных файлах. Так что вы можете использовать это в вашем app.config/web.config:
<appSettings configSource="appsettings.config" />
<connectionStrings configSource="connection.config" />
<system.net>
<mailSettings>
<smtp configSource="smtp.config"/>
</mailSettings>
</system.net>
Обычно я делаю эти специфичные для конфигурации разделы в отдельных файлах, в подпапке с именем ConfigFiles (в зависимости от корня решения или на уровне проекта). Я определяю файл для каждой конфигурации, например, smtp.config.Debug и smtp.config.Release.
Затем вы можете определить событие перед сборкой следующим образом:
copy $(ProjectDir)ConfigFiles\smtp.config.$(ConfigurationName) $(TargetDir)smtp.config
В групповой разработке вы можете изменить это, включив в соглашение%COMPUTERNAME% и / или%USERNAME%.
Конечно, это подразумевает, что целевые файлы (x.config) НЕ должны помещаться в систему контроля версий (так как они генерируются). Вы все равно должны добавить их в файл проекта и установить для их свойства выходного типа значение "всегда копировать" или "копировать, если новее".
Простой, расширяемый, и он работает для всех типов проектов Visual Studio (консоль, winforms, wpf, web).
Вы можете использовать отдельный файл конфигурации для каждой конфигурации, например, app.Debug.config, app.Release.config, а затем использовать переменную конфигурации в файле проекта:
<PropertyGroup>
<AppConfig>App.$(Configuration).config</AppConfig>
</PropertyGroup>
После этого будет создан правильный файл ProjectName.exe.config в зависимости от конфигурации, в которую вы встраиваете.
Я написал хорошее расширение для автоматизации преобразования app.config, подобное встроенному преобразованию конфигурации проекта веб-приложения.
Самое большое преимущество этого расширения в том, что вам не нужно устанавливать его на всех сборочных машинах.
Установите "Средство преобразования конфигурации" в Visual Studio из Marketplace и перезапустите VS. Вы также сможете увидеть преобразование предварительного просмотра меню для app.config.
https://marketplace.visualstudio.com/items?itemName=GolanAvraham.ConfigurationTransform
Я наткнулся на следующую статью, которая выглядит немного проще, но я сам не пробовал.
http://fknut.blogspot.com/2009/11/appconfig-transformation-with-new.html
Кроме того, в MS Connect есть запрос на добавление функциональности, который может стоить проголосовать, так что он будет включен во все разделы следующего SP или версии.
https://connect.microsoft.com/VisualStudio/feedback/details/564414
Просто небольшое улучшение в решении, которое, кажется, теперь публикуется везде:
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
- то есть, если вы не планируете остаться с текущей версией VS навсегда
В итоге я выбрал немного другой подход. Я выполнил шаги Дэна до шага 3, но добавил еще один файл: App.Base.Config. Этот файл содержит параметры конфигурации, которые вы хотите в каждом сгенерированном App.Config. Затем я использую BeforeBuild (с добавлением Юрия в TransformXml), чтобы преобразовать текущую конфигурацию с базовой конфигурацией в App.config. Затем процесс сборки использует преобразованный файл App.config как обычно. Тем не менее, одна неприятность заключается в том, что вы как бы хотите исключить постоянно изменяющийся App.config из контроля версий впоследствии, но другие файлы конфигурации теперь зависят от него.
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="BeforeBuild" Condition="exists('app.$(Configuration).config')">
<TransformXml Source="App.Base.config" Transform="App.$(Configuration).config" Destination="App.config" />
</Target>
Я решаю эту проблему с помощью этого инструмента http://ctt.codeplex.com/. Я использую его со скриптом CCNet/nAnt для создания пакетов.
Я создал другую альтернативу той, которую опубликовал Вишал Джоши, где снято требование изменить действие построения на Контент, а также реализована базовая поддержка развертывания ClickOnce. Я говорю простой, потому что я не тестировал его полностью, но он должен работать в типичном сценарии развертывания ClickOnce.
Решение состоит из одного проекта MSBuild, который после импорта в существующий проект приложения Windows (*.csproj) расширяет процесс сборки, чтобы предусматривать преобразование app.config.
Вы можете прочитать более подробное объяснение в Visual Studio App.config XML Transformation, а файл проекта MSBuild можно загрузить с GitHub.
Если вы используете TFS онлайн (облачная версия) и хотите преобразовать App.Config в проект, вы можете сделать следующее без установки каких-либо дополнительных инструментов. Из VS => Выгрузить проект => Редактировать файл проекта => Перейти в конец файла и добавить следующее:
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterBuild" Condition="Exists('App.$(Configuration).config')">
<TransformXml Source="App.config" Transform="App.$(Configuration).config" Destination="$(OutDir)\$(AssemblyName).dll.config" />
AssemblyFile и Destination работают для локального использования и TFS онлайн (Облачный) сервер.
Предлагаемое решение не будет работать, если на ссылку на библиотеку классов с файлом конфигурации ссылается другой проект (в моем случае это была библиотека рабочего проекта Azure). Он не будет копировать правильный преобразованный файл из obj
папка в bin\##configuration-name##
папка. Чтобы он работал с минимальными изменениями, вам нужно изменить AfterCompile
цель для BeforeCompile
:
<Target Name="BeforeCompile" Condition="exists('app.$(Configuration).config')">
Примечание: Из - за репутации я не могу комментировать bdeem"s пост. Вместо этого я публикую свои выводы в качестве ответа.
После bdeem"сек поста, я сделал следующее (в порядке убывания):
1. Я изменил
[project].csproj
файл. Добавил
<Content Include="" />
теги к
ItemGroup
для разных
config
файлы и сделал их зависимыми от оригинала
config
файл.
Примечание: использование
<None Include="" />
не будет работать с трансформацией.
<!-- App.config Settings -->
<!-- Create App.($Configuration).config files here. -->
<Content Include="App.config" />
<Content Include="App.Debug.config">
<DependentUpon>App.config</DependentUpon>
</Content>
<Content Include="App.Release.config">
<DependentUpon>App.config</DependentUpon>
</Content>
2. Внизу
[project].csproj
файл (до закрытия
</Project>
тег), я импортировал
${MSBuildToolsPath\Microsoft.CSharp.targets
файл, добавил
UsingTask
чтобы преобразовать XML и добавил
Target
скопировать преобразованный
App.config
файл в место вывода.
Обратите внимание
Target
также перезапишет
App.Config
в локальном каталоге, чтобы сразу увидеть изменения, работающие локально. В
Target
также использует
Name="Afterbuild"
свойство, чтобы файлы конфигурации можно было преобразовать после создания исполняемых файлов. По непонятным мне причинам при использовании конечных точек WCF, если я использую
Name="CoreCompile"
, Я получу предупреждения об атрибутах службы.
Name="Afterbuild"
решил это.
<!-- Task to transform the App.config using the App.($Configuration).config file. -->
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<!-- Only compile the App.config if the App.($Configuration).config file exists. -->
<!-- Make sure to use the AfterBuild name instead of CoreCompile to avoid first time build errors and WCF endpoint errors. -->
<Target Name="AfterBuild" Condition="exists('App.$(Configuration).config')">
<!-- Generate transformed App.config in the intermediate output directory -->
<TransformXml Source="App.config" Destination="$(IntermediateOutputPath)$(TargetFileName).config" Transform="App.$(Configuration).config" />
<!-- Modify the original App.config file with the transformed version. -->
<TransformXml Source="App.config" Destination="App.config" Transform="App.$(Configuration).config" />
<!-- Force build process to use the transformed configuration file from now on. -->
<ItemGroup>
<AppConfigWithTargetPath Remove="App.config" />
<AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
<TargetPath>$(TargetFileName).config</TargetPath>
</AppConfigWithTargetPath>
</ItemGroup>
</Target>
</Project>
3. Вернулся в Visual Studio и перезагрузил измененные файлы.
4. Добавил вручную
App.*.config
файлы в проект. Это позволило им сгруппироваться под исходным
App.config
файл.
Примечание. Убедитесь, что
App.*.config
файлы имеют правильную структуру XML.
<?xml version="1.0" encoding="utf-8"?>
<!-- For more information on using web.config transformation visit https://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings>
<add name="myConn" connectionString=""; Initial Catalog=; User ID=; Password=;" xdt:Transform="SetAttributes" xdt:Locator="Match(name)" />
</connectionStrings>
</configuration>
5. Перестроил проект.
Еще один вариант ответа @bdeem с использованием Visual Studio 2019 и 2022. Моя проблема заключалась в том, что при использовании этого решения
App.config
перезаписывался, и, поскольку он находится в системе управления версиями, это не вариант.
Решение для меня состояло в том, чтобы преобразовать файл конфигурации непосредственно в выходной каталог.
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterBuild" Condition="Exists('App.$(Configuration).config')">
<!-- Generate transformed app config to the output directory -->
<TransformXml Source="App.config" Destination="$(OutDir)\$(TargetFileName).config" Transform="App.$(Configuration).config" />
</Target>
Дополнительным преимуществом этого решения является то, что оно немного короче исходного решения.