Перетворення App.Config для проектів, які не є веб-проектами у Visual Studio?


546

Для веб-додатків Visual Studio 2010 у нас є функції Config Transformation, за допомогою яких ми можемо підтримувати декілька файлів конфігурації для різних середовищ. Але ця ж функція недоступна для файлів App.Config для служб Windows / WinForms або додатків консолі.

Тут запропоновано вирішення: Застосування магії XDT до App.Config .

Однак це не є простим і вимагає певних кроків. Чи є простіший спосіб досягти того ж для файлів app.config?


Я натрапив на наступну статтю, яка виглядає трохи простіше, але я сама не пробувала. fknut.blogspot.com/2009/11/… Крім того, на MS Connect є запит на функцію, який, можливо, варто проголосувати, щоб він потрапляв упродовж наступного SP або версії. connect.microsoft.com/VisualStudio/feedback/details/564414
Kim R

Відповіді:


413

Це працює зараз з Visual Studio AddIn, обробленим у цій статті: SlowCheetah - синтаксис трансформації Web.config, який тепер узагальнений для будь-якого файлу конфігурації XML .

Ви можете клацнути правою кнопкою миші на веб-конфіг і натиснути "Додати конфігурувати перетворення". Коли ви це зробите, ви отримаєте web.debug.config і web.release.config. Якщо ви хочете, ви можете створити web.wwhat.config, якщо ім'я співпадає з профілем конфігурації. Ці файли - це лише зміни, які ви хочете внести, а не повна копія вашого web.config.

Ви можете подумати, що ви хочете використовувати XSLT для перетворення web.config, але, хоча вони інтуїтивно відчувають себе, це насправді дуже багатослівно.

Ось два перетворення, один з використанням XSLT і той самий з використанням синтаксису / простору імен XML Document Transform. Як і у всіх речах, у 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>

О, це солодко! Мати додаток із численними конфігураційними файлами (log4net, nHibernate, web.config) і пам’ятати, що змінити їх все було трохи боляче. Я не з нетерпінням чекав переміщення коду в CruiseControl.NET, але схоже, що це теж вітер.
DilbertDave

10
FYI, SlowCheetah був фантастичним розширенням, яке тепер не підтримуватиметься після VS 2014. За автором, Саєдом Ібрагімом Хашімі , sedodream.com/2014/08/11/… .
беріть

5
@andrewb, я прочитав це тут ; проте це було рік тому. Переглянувши нитку та прочитавши коментарі, схоже, хтось надав версію, яка працює тут з VS2015 .
Аніл Ната

2
Ідеально співпрацюючи з Visual Studio 2017 та Visual STudio 2019
Guilherme de Jesus Santos

1
Це тут в даний час
Hugo Фрейтас

573

Я спробував кілька рішень, і ось найпростіший, який я особисто знайшов.
Ден зазначив у коментарях, що оригінальний пост належить Олегу Сичу - дякую, Олегу!

Ось інструкція:

1. Додайте XML-файл для кожної конфігурації до проекту.

Зазвичай у вас будуть Debugі Releaseконфігурації, так називайте свої файли App.Debug.configі App.Release.config. У своєму проекті я створив конфігурацію для кожного виду оточення, тож, можливо, ви захочете експериментувати з цим.

2. Вивантажте проект і відкрийте .csproj файл для редагування

Visual Studio дозволяє редагувати .csproj файли прямо в редакторі - потрібно лише спочатку завантажити проект. Потім клацніть правою кнопкою миші та виберіть Правка <ProjectName> .csproj .

3. Прив’яжіть конфігураційні файли програми. *. До основної програми 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. Активуйте магію перетворень (необхідна лише для версій Visual Studio до VS2017 )

У кінці файлу після

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

4
Дякую тоні за це! Одне зауваження, якщо ви додасте нові .config файли до проекту після редагування csproj, вони відображатимуться в групі під App.config. Я додав один перед редагуванням csproj і фактично закінчив два посилання на нього, одне згруповане та одне сольне.
Jeff Swensen

8
Одна з проблем цього підходу полягає в тому, що, переглянувши вкладку "Опублікувати" у властивостях проекту, а потім натиснути кнопку "Файли програми", ви помітите, що app.config, app.Debug.config, app.Release.config змушені розгортатися як частина процесу публікації. Звичайно, ви також отримали правильний файл MyApp.exe.config, але я не хочу, щоб цей додатковий багаж розгортався. Потрібен спосіб зберегти додаток. *. Конфігураційні файли в проекті як <Ніхто> замість <Зміст>.
Лі Гріссом

6
Єдиною проблемою, яку це дещо не вистачає, є відповідь, спочатку отримана від Олега Сича. Якщо у вашому індивідуальному додатку. (Env) .configs ви НЕ перераховуєте '<конфігурацію xmlns: xdt = " schemas.microsoft.com/XML-Document-Transform "> "і щось на кшталт <appSettings xdt: Transform =" Замінити "> або атрибути, які роблять подібні речі на лініях налаштування, це не працюватиме. Цей останній біт інформації є ключовим, і як тільки я додав його, підкажіть, що все почало працювати.
djangojazz

24
Ви могли б замінити v10.0з , v$(VisualStudioVersion)щоб переконатися , що ваш проект дійсно працює з усіма більш пізніми версіями VS.
Тібо Д.

14
У мене виникла помилка MSBuild помилка MSB3021: Неможливо скопіювати файл. Не вдалося знайти файл 'obj \ Release \ ConsoleApp.exe' під час збирання. Тож я трохи змінюю рішення, щоб повторно використовувати цільовий розділ <Target Name = "AfterBuild"> замість того, щоб створити новий, як у рішенні
asidis

137

Ще одне знайдене нами рішення - НЕ використовувати перетворення, а просто мати окремий файл конфігурації, наприклад app.Release.config. Потім додайте цей рядок у файл csproj.

  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
    <AppConfig>App.Release.config</AppConfig>
  </PropertyGroup>

Це не тільки створить правильний файл myprogram.exe.config, але якщо ви використовуєте проект настройки та розгортання у Visual Studio для створення MSI, він змусить проект розгортання використовувати правильний файл конфігурації під час упаковки.


6
Незгадані чудеса MSBuild. Тепер мені цікаво, що ще можливо. Btw. це працює також для розгортання за кліком безпосередньо від VS (на відміну від більш високих голосів відповідей).
Борис Б.

4
Зміни можуть стати обтяжливими та схильними до помилок, якщо конфігурації містять багато записів, які є єдиними для всіх збірок. Зараз вирішуємо проблему, коли одна .config одного середовища пропустила зміну, і, звичайно, це було виробництво.
jeepwran

1
Наявність двох копій конфігураційного файлу не є проблемою, якщо розробники не ті, хто підтримують його вручну.
anIBMer

1
Це прекрасно, працює як шарм! Я вставив лише <AppConfig>App.Release.config</AppConfig>рядок всередині існуючої <PropertyGroupумови для Releaseконфігурації, і IDE показав чітко внизу рядок <AppConfig>... рядок, кажучи, що його немає в схемі чи щось таке, але я все одно зберег файл і перезавантажив файл проекту та зробив збірку у Releaseналаштуваннях і це працювало!
Шива

1
Цим ви втратите функціональність дизайнера налаштувань.
Ondřej

33

З мого досвіду, мені потрібно зробити конкретні умови, такі як рядки підключення, програми та часто налаштування smpt. Система config дозволяє вказати ці речі в окремих файлах. Отже, ви можете використовувати це у своєму 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).


У мене точно така ж конфігурація, що і у вас. Але у мене є проблеми з трансформацією smtp-файлу. Чи можете ви включити оригінал та перетворення? Це моє: Базовий файл: <?xml version="1.0"?> <smtp deliveryMethod="SpecifiedPickupDirectory"> <specifiedPickupDirectory pickupDirectoryLocation="C:\mail"/> <network host="localhost"/> </smtp> Перетворення:<?xml version="1.0"?> <smtp xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" xdt:Transform="Replace" from="user@email.com" deliveryMethod="Network"> <network .../> </smtp>
jgarza

Я не впевнений, що розумію. У цій конфігурації я нічого не перетворюю, це просто копіювання файлів ...
jeroenh

О, я не бачив копіювальної частини. Я перетворюю конфігурацію, а не просто копіюю її. Все одно, дякую.
jgarza

Мені подобається це рішення. Одна невелика пропозиція: у прикладі копіювання над джерелом та цільовими аргументами для копіювання слід оточити лапки; інакше програма Pre-Build не зможе отримати каталоги з простором у їх назві
vandre

32

Надихнувшись Олегом та іншими особами у цьому питанні, я зробив рішення https://stackoverflow.com/a/5109530/2286801 на крок далі, щоб увімкнути наступне.

  • Працює з 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-файл для кожної конфігурації до проекту.

Зазвичай у вас будуть конфігурації налагодження та випуску, щоб назвати свої файли App.Debug.config та App.Release.config. У своєму проекті я створив конфігурацію для кожного виду враження, щоб ви могли експериментувати з цим.

2. Вивантажте проект і відкрийте .csproj файл для редагування

Visual Studio дозволяє редагувати .csproj прямо в редакторі - вам потрібно спочатку розвантажити проект. Потім клацніть на ньому правою кнопкою миші та виберіть Правка .csproj.

3. Прив’яжіть конфігураційні файли програми. *. До основної програми App.config

Знайдіть розділ файлу проекту, який містить усі посилання на конфігурацію App.config та App. *., Та замініть наступним чином. Ви помітите, що ми використовуємо None замість Вмісту.

<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" />

Готово!


1
Пробували в VS Community 2015 RC, і він ігнорує файл app.Debug.config, який у мене є.
Хайнестар

Я успішно використав прийняту відповідь в одному проекті WinForms .. але з певних причин не вдалося застосувати прийнятий анс. до іншого проекту WinForms (усе в тому ж самому рішенні). Ця відповідь від @bdeem - це моя нова любов - як це правильно взаємодіяло з моїм проектом MSI - велике спасибі!
bkwdesign

Схоже, це не спрацювало у VS 2015. Я оновив VisualStudioVersion з 10 на 12, але без кісток. Будь-які ідеї?
Синестетик

@Sinaesthetic Ви можете дати нам більше деталей? VS 2015 Ultimate, Community тощо. VB.NET, C #, помилки?
беріть

VS2015 Enterprise. Жодних помилок. Це просто нічого не робить.
Сінестетик

27

Ви можете використовувати окремий конфігураційний файл для кожної конфігурації, наприклад app.Debug.config, app.Release.config, а потім використовувати змінну конфігурації у файлі проекту:

<PropertyGroup>
    <AppConfig>App.$(Configuration).config</AppConfig>
</PropertyGroup>

Потім буде створено правильний файл ProjectName.exe.config залежно від конфігурації, в якій ви будуєте.


Дякую, я не використав твій точний приклад для вирішення проблеми, яка була у мене, але твій приклад змусив мене задуматися і привів мене до ще одного дуже схожого сулюту, використовуючи завдання Copy.
jpierson

Спробував це під RC VS 2015 Community RC і він будує, але потім ігнорує вміст програми. *. Я додав.
Хайнестар

14

Я написав хороший розширення для автоматизації перетворення app.config , як один , побудований в веб - додаток Project Configuration Transform

Найбільшою перевагою цього розширення є те, що вам не потрібно встановлювати його на всіх складальних машинах


1
Дуже корисне розширення, особливо зараз, коли повільний гепард переходить у режим технічного обслуговування, і він може не підтримуватися в майбутньому.
dthrasher

Так, люди повинні перестати йти на уповільнення гепарду як рішення для цього, коли ця функціональність тепер підтримується завданням msx create transformxml. Архітектор SW в моїй команді представив повільний гепард в наш проект і створив налагодження, сценічні та релізні перетворення всіх наших конфігурацій, більшість з яких не потребувала трансформації. Само собою зрозуміло, що в той момент, коли він пішов, я витягнув повільний гепард і зараз ми просто використовуємо єдине завдання transformxml на web.config. Ааааа, простота. Не кажучи про те, що повільний гепард не мав свого часу і місця.
HarryTuttle

5

Встановіть "Інструмент трансформації конфігурації" у Visual Studio з Marketplace та перезапустіть VS. Ви також зможете побачити трансформацію попереднього перегляду меню для app.config.

https://marketplace.visualstudio.com/items?itemName=GolanAvraham.ConfigurationTransform


1
Це прекрасно працює і вимагає дуже мало зусиль чи думок. Цінується. Дякую. ("Перетворення попереднього перегляду" не працює, але "додавання перетворень" ідеально працює без проблем у VS 2017). Також, здається, часто надходять оновлення.
adudley

1
велике спасибі за рішення, за сценою воно робить саме те, що пояснив Дан Абрамов вище, не забруднивши руку
Мохаммед Давуд Ансарі

Це остаточне рішення. Попередній перегляд, здається, працює з VS 2019.
Чемпіон Кайла

1
Мені подобається, але я виявив, що він не підтримує інші файли, які не містять app.config, без редагування csproj. Але все-таки чудово, хоча побачити попередній перегляд.
Ian1971

4

Тож я підходив дещо іншим підходом. Я дотримувався кроків Дена через крок 3, але додав ще один файл: App.Base.Config. Цей файл містить необхідні параметри конфігурації у всіх створених програмах App.Config. Потім я використовую BeforeBuild (з додаванням Юрія до TransformXml), щоб перетворити поточну конфігурацію з конфігурацією Base в 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>

3

Лише невелике вдосконалення рішення, яке, здається, розміщено всюди зараз:

<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
  • тобто якщо ви не плануєте назавжди залишатися з поточною версією VS

Чи можете ви, будь ласка, пояснити вам трохи відповіді або дати джерела, щоб це пояснити?
roydukkey

4
Схоже, $(VisualStudioVersion)це не встановлено при використанні MSBuild безпосередньо.
Джеремі Сміт

Це має бути коментар до stackoverflow.com/a/5109530/2003763 (я щойно додав ту саму інформацію, що й коментар)
Thibault D.

2

Я створив ще одну альтернативу тій, яку опублікував Вішал Джоші, де вимога зміни дії збірки на Вміст знято, а також застосував базову підтримку розгортання ClickOnce. Я кажу основне, тому що я не перевіряв його ретельно, але він повинен працювати в типовому сценарії розгортання ClickOnce.

Рішення складається з одного проекту MSBuild, який після імпорту до існуючого проекту додатків Windows (* .csproj) розширює процес збирання, щоб передбачити перетворення app.config.

Більш детальне пояснення ви можете прочитати на Visual Studio App.config XML Transformation, а файл проекту MSBuild можна завантажити з GitHub .


1

Якщо ви використовуєте 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-сервера в Інтернеті (Cloud).


0

запропоноване рішення не працюватиме, коли бібліотека класів із файлом config посилається на інший проект (у моєму випадку це бібліотека проектів Azure Worker). Він не скопіює правильний перетворений файл із objпапки в bin\##configuration-name##папку. Щоб вона працювала з мінімальними змінами, потрібно змінити AfterCompileціль на BeforeCompile:

<Target Name="BeforeCompile" Condition="exists('app.$(Configuration).config')">
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.