Transformação App.Config para projetos que não são projetos da Web no Visual Studio?


546

Para o aplicativo baseado na Web do Visual Studio 2010, temos os recursos de Transformação de configuração, pelos quais podemos manter vários arquivos de configuração para diferentes ambientes. Mas o mesmo recurso não está disponível para arquivos App.Config para Windows Services / WinForms ou Console Application.

Há uma solução alternativa disponível, conforme sugerido aqui: Aplicando a magia XDT ao App.Config .

No entanto, não é simples e requer várias etapas. Existe uma maneira mais fácil de obter o mesmo para arquivos app.config?


Eu me deparei com o artigo a seguir, que parece um pouco mais simples, mas ainda não tentei. fknut.blogspot.com/2009/11/… Além disso, há uma solicitação de recurso no MS Connect que pode valer a pena votar, para que isso seja incluído em todos os setores no próximo SP ou versão. connect.microsoft.com/VisualStudio/feedback/details/564414
Kim R

Respostas:


413

Isso funciona agora com o Visual Studio AddIn tratado neste artigo: SlowCheetah - Web.config Sintaxe de transformação agora generalizada para qualquer arquivo de configuração XML .

Você pode clicar com o botão direito do mouse em seu web.config e clicar em "Adicionar transformações de configuração". Ao fazer isso, você obtém um web.debug.config e um web.release.config. Você pode criar um web.whatever.config, se quiser, desde que o nome esteja alinhado com um perfil de configuração. Esses arquivos são apenas as alterações que você deseja fazer, não uma cópia completa do seu web.config.

Você pode pensar que gostaria de usar o XSLT para transformar um web.config, mas enquanto eles se sentem intuitivamente certos, é realmente muito detalhado.

Aqui estão duas transformações, uma usando XSLT e a mesma usando a sintaxe / namespace XML Document Transform. Como em todas as coisas, há várias maneiras no XSLT de fazer isso, mas você entende a ideia geral. XSLT é uma linguagem generalizada de transformação em árvore, enquanto essa implementação é otimizada para um subconjunto específico de cenários comuns. Mas, a parte interessante é que cada transformação XDT é um plug-in .NET, para que você possa criar o seu próprio.

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

Ou a mesma coisa através da transformação de implantação:

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
   <appSettings>
      <add name="NewSetting" value="New Setting Value" xdt:Transform="Insert"/>
   </appSettings>
</configuration>

Oh, isso é doce! Ter um aplicativo com vários arquivos de configuração (log4net, nHibernate, web.config) e lembrar de alterá-los todos foi um pouco trabalhoso. Eu não estava ansioso para mudar o código para o CruiseControl.NET também, mas parece que também é fácil.
DilbertDave

10
Para sua informação, o SlowCheetah era uma extensão fantástica que agora não será suportada após o VS 2014. Pelo autor, Sayed Ibrahim Hashimi, sedodream.com/2014/08/11/… .
Bdeem 01/10/14

5
@andrewb, eu li isso aqui ; no entanto, isso foi há um ano. Depois de revisitar o tópico e ler os comentários, parece que alguém forneceu uma versão que funciona com o VS2015 aqui .
Anil Natha

2
Trabalhando perfeitamente com o Visual Studio 2017 e o Visual STudio 2019
Guilherme de Jesus Santos

1
Está aqui agora
Hugo Freitas

573

Tentei várias soluções e aqui está a mais simples que encontrei pessoalmente.
Dan apontou nos comentários que o post original pertence a Oleg Sych - obrigado, Oleg!

Aqui estão as instruções:

1. Adicione um arquivo XML para cada configuração ao projeto.

Normalmente você terá Debuge Releaseconfigurações para nomear seus arquivos App.Debug.confige App.Release.config. No meu projeto, criei uma configuração para cada tipo de ambiente, então você pode experimentar isso.

2. Descarregue o projeto e abra o arquivo .csproj para edição

O Visual Studio permite editar arquivos .csproj diretamente no editor - basta descarregar o projeto primeiro. Em seguida, clique com o botão direito do mouse e selecione Editar <ProjectName> .csproj .

3. Vincule os arquivos App. *. Config ao App.config principal

Localize a seção arquivo de projeto que contém todos App.confige App.*.configreferências. Você notará que as ações de criação estão definidas para None:

<None Include="App.config" />
<None Include="App.Debug.config" />
<None Include="App.Release.config" />

Primeiro, defina a ação de compilação para todos eles Content.
Em seguida, torne todos os arquivos específicos da configuração dependentes dos principais, App.configpara que o Visual Studio os agrupe da mesma forma que cria arquivos de código e de designer.

Substitua XML acima por um abaixo:

<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. Ative a mágica de transformações (necessária apenas para as versões do Visual Studio anteriores ao VS2017 )

No final do arquivo após

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

e antes da final

</Project>

insira o seguinte 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>

Agora você pode recarregar o projeto, construí-lo e desfrutar de App.configtransformações!

Para sua informação

Certifique-se de que seus App.*.configarquivos tenham a configuração correta como esta:

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
     <!--magic transformations here-->
</configuration>

4
Muito obrigado por isso! Uma observação: se você adicionar os novos arquivos .config ao projeto após editar o csproj, eles aparecerão agrupados em App.config. Eu adicionei um antes de editar o csproj e, basicamente, acabei com dois links, um agrupado e um solo.
precisa

8
Um problema com essa abordagem é que, quando você olha para a guia "Publicar" nas propriedades do projeto e clica no botão "Arquivos de aplicativos" ... você perceberá que app.config, app.Debug.config, app.Release.config são forçados a serem implantados como parte do processo de publicação. Claro, você também obtém o arquivo MyApp.exe.config correto, mas não quero que essa bagagem extra seja implantada. É preciso haver uma maneira de manter os arquivos app. *. Config no projeto como <Nenhum> em vez de <Content>.
Lee Grissom

6
O único problema que isso deixa de fora para alguns é que a resposta originalmente retirada de Oleg Sych deixa de fora uma peça fundamental. Se em seu aplicativo individual. (Env) .configs você NÃO listar '<configuration xmlns: xdt = " schemas.microsoft.com/XML-Document-Transform ">' e algo como <appSettings xdt: Transform = "Replace"> ou atributos que fazem coisas semelhantes nas linhas de configuração, ele não funcionará. Esta última informação é essencial e, depois que a adicionei, tudo começou a funcionar.
djangojazz

24
Você pode substituir v10.0por v$(VisualStudioVersion)para garantir que seu projeto funcione com todas as versões posteriores do VS.
Thibault D.

14
Eu tive um erro MSBuild error MSB3021: Não foi possível copiar o arquivo. Não foi possível encontrar o arquivo 'obj \ Release \ ConsoleApp.exe' durante a compilação. Então eu mudar um pouco a solução para alvo reutilização <Meta Name = "AfterBuild"> seção em vez de criar uma nova como na solução
asidis

137

Outra solução que encontrei NÃO é usar as transformações, mas apenas ter um arquivo de configuração separado, por exemplo, app.Release.config. Em seguida, adicione esta linha ao seu arquivo csproj.

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

Isso não apenas gerará o arquivo myprogram.exe.config correto, mas se você estiver usando o Projeto de Instalação e Implantação no Visual Studio para gerar o MSI, forçará o projeto de implantação a usar o arquivo de configuração correto ao compactar.


6
As incontáveis ​​maravilhas do MSBuild. Agora eu me pergunto o que mais é possível. Btw. isso também funciona para implantações de cliques em um diretamente do VS (em contraste com as respostas com maior número de votos).
Boris B.

4
As alterações podem se tornar onerosas e propensas a erros se as configurações contiverem muitas entradas iguais para todas as compilações. Lidando com um problema no momento em que o .config de um ambiente perdeu uma mudança e, é claro, foi a produção.
Jeepwran

1
Ter duas cópias do arquivo de configuração não é um problema, desde que não sejam os desenvolvedores que os mantenham manualmente.
anIBMer 26/08/15

1
Isso é lindo, funciona como um encanto! Eu colei apenas a <AppConfig>App.Release.config</AppConfig>linha dentro da <PropertyGroupcondição existente para a Releaseconfiguração e o IDE mostrou uma linha ondulada abaixo da <AppConfig>linha ... dizendo que não estava no esquema ou algo assim, mas salvei o arquivo de qualquer maneira e recarreguei o arquivo do projeto e fiz uma compilação na Releaseconfiguração e funcionou!
Shiva

1
Com isso, você perderá a funcionalidade do designer de configurações.
Ondřej

33

Na minha experiência, as coisas que preciso tornar específicas do ambiente são: cadeias de conexão, configurações de aplicativos e configurações frequentemente smpt. O sistema de configuração permite especificar essas coisas em arquivos separados. Então você pode usar isso em seu app.config / web.config:

 <appSettings configSource="appsettings.config" />
 <connectionStrings configSource="connection.config" />
 <system.net>
    <mailSettings>
       <smtp configSource="smtp.config"/>
    </mailSettings>
 </system.net>

O que normalmente faço é colocar essas seções específicas da configuração em arquivos separados, em uma subpasta chamada ConfigFiles (na raiz da solução ou no nível do projeto, depende). Eu defino um arquivo por configuração, por exemplo, smtp.config.Debug e smtp.config.Release.

Em seguida, você pode definir um evento de pré-construção da seguinte maneira:

copy $(ProjectDir)ConfigFiles\smtp.config.$(ConfigurationName) $(TargetDir)smtp.config

No desenvolvimento da equipe, você pode ajustar isso ainda mais, incluindo% COMPUTERNAME% e / ou% USERNAME% na convenção.

Obviamente, isso implica que os arquivos de destino (x.config) NÃO devem ser colocados no controle de origem (uma vez que são gerados). Você ainda deve adicioná-los ao arquivo do projeto e definir sua propriedade de tipo de saída como 'copy always' ou 'copy if newer'.

Simples, extensível e funciona para todos os tipos de projetos do Visual Studio (console, winforms, wpf, web).


Eu tenho exatamente a mesma configuração que você tem. Mas tenho problemas para transformar o arquivo smtp. Você pode incluir o original e a transformação? Estes são meus: O arquivo de base: <?xml version="1.0"?> <smtp deliveryMethod="SpecifiedPickupDirectory"> <specifiedPickupDirectory pickupDirectoryLocation="C:\mail"/> <network host="localhost"/> </smtp> A transformação:<?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

Eu não tenho certeza se entendi. Nesta configuração eu não transformar qualquer coisa, é só copiar arquivos ...
jeroenh

Ah, eu não vi a parte da cópia. Transformo a configuração em vez de apenas copiá-la. Obrigado mesmo assim.
jgarza

Eu gosto desta solução. Uma pequena sugestão: no exemplo de cópia acima, os argumentos de origem e destino para cópia devem estar entre aspas; caso contrário pré-compilação irá falhar para diretórios com espaço em seu nome
Vandré

32

Inspirado por Oleg e outros nesta questão, levei a solução https://stackoverflow.com/a/5109530/2286801 um passo adiante para permitir o seguinte.

  • Funciona com ClickOnce
  • Trabalha com projetos de Instalação e Implantação no VS 2010
  • Funciona com o VS2010, 2013, 2015 (não testou 2012, embora deva funcionar também).
  • Funciona com o Team Build. (Você deve instalar o A) Visual Studio ou B) Microsoft.Web.Publishing.targets e Microsoft.Web.Publishing.Tasks.dll

Esta solução funciona executando a transformação app.config antes que o app.config seja referenciado pela primeira vez no processo MSBuild. Ele usa um arquivo de destinos externos para facilitar o gerenciamento em vários projetos.

Instruções:

Etapas semelhantes à outra solução. Eu citei o que permanece o mesmo e o incluí para completude e comparação mais fácil.

0. Adicione um novo arquivo ao seu projeto chamado 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. Adicione um arquivo XML para cada configuração ao projeto.

Normalmente, você terá configurações de Debug e Release, para nomear seus arquivos App.Debug.config e App.Release.config. No meu projeto, criei uma configuração para cada tipo de ambiente, para que você possa experimentar isso.

2. Descarregue o projeto e abra o arquivo .csproj para edição

O Visual Studio permite editar .csproj diretamente no editor - você só precisa descarregar o projeto primeiro. Em seguida, clique com o botão direito do mouse e selecione Editar .csproj.

3. Vincule os arquivos App. *. Config ao App.config principal

Localize a seção do arquivo do projeto que contém todas as referências App.config e App. *. Config e substitua da seguinte maneira. Você notará que usamos Nenhum em vez de Conteúdo.

<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. Ativar transformações mágicas

No final do arquivo após

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

e antes da final

</Project>

insira o seguinte XML:

<Import Project="AppConfigTransformation.targets" />

Feito!


1
Tentei no VS Community 2015 RC e ignora o arquivo app.Debug.config que tenho.
Khainestar 29/10

Usei com sucesso a resposta aceita em um projeto WinForms .. mas, por algum motivo desconcertante, não foi possível aplicar as ans aceitas. para outro projeto WinForms (todos na mesma solução). Esta resposta do @bdeem é meu novo favorito - como ele interoperou corretamente com o meu projeto MSI - muito obrigado!
Bkwdesign

Isso não parece funcionar no VS 2015. Atualizei o VisualStudioVersion de 10 para 12, mas não há dados. Alguma ideia?
Sinaesthetic

@ Sinestésico Você pode nos dar mais detalhes? VS 2015 Ultimate, Comunidade, etc. VB.NET, C #, Algum erro?
bdeem

VS2015 Enterprise. Sem erros. Simplesmente não faz nada.
Sinaesthetic

27

Você pode usar um arquivo de configuração separado por configuração, por exemplo, app.Debug.config, app.Release.config e, em seguida, usar a variável de configuração no seu arquivo de projeto:

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

Isso criará o arquivo ProjectName.exe.config correto, dependendo da configuração em que você está construindo.


Obrigado, eu não usei seu exemplo exato para resolver o problema que estava tendo, mas seu exemplo me fez pensar e me levou a outra alma muito semelhante usando a tarefa Copiar.
jpierson

Tentei isso no VS 2015 Community RC e ele constrói, mas depois ignora o conteúdo do aplicativo. *. Config que adicionei.
Khainestar 11:15

14

Eu escrevi uma boa extensão para automatizar a transformação app.config como a que foi criada na Transformação de Configuração de Projetos de Aplicativos da Web

A maior vantagem dessa extensão é que você não precisa instalá-la em todas as máquinas de compilação


1
Extensão muito útil, especialmente agora que o Slow Cheetah está entrando no modo de manutenção e pode não ser suportado no futuro.
dthrasher 27/02

Sim, as pessoas devem parar de ficar com o guepardo lento como solução para isso quando essa funcionalidade agora é suportada pela tarefa msbuild do transformxml. Um arquiteto de sw da minha equipe introduziu a chita lenta de maneira excessivamente zelosa em nosso projeto e criou transformações de depuração, estágio e liberação de todas as nossas configurações, a maioria das quais não precisava de transformação. Escusado será dizer que, no momento em que ele saiu, puxei a chita lenta e agora usamos apenas uma única tarefa transformxml no web.config. Ahhhhh, simplicidade. Para não dizer que a chita lenta não tinha seu tempo e lugar.
precisa saber é o seguinte

5

Instale a "Ferramenta de transformação de configuração" no Visual Studio no Marketplace e reinicie o VS. Você também poderá ver a transformação de visualização do menu para app.config.

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


1
Isso funciona perfeitamente e requer muito pouco esforço ou pensamento. Muito apreciado. obrigado. (a 'transformação de visualização' não funciona, mas a 'adição de transformações' funciona perfeitamente sem problemas no VS 2017). Também parece receber atualizações com frequência.
precisa saber é o seguinte

1
muito obrigado pela solução, nos bastidores, ele faz exatamente o que Dan Abramov explicou acima, sem sujar a mão
Mohammed Dawood Ansari

Esta é a solução definitiva. A pré-visualização parece funcionar muito bem com o VS 2019.
Kyle Champion

1
Adorei, mas achei que não suportava outros arquivos que não sejam app.config sem alguma edição do csproj. Ainda é ótimo ver a pré-visualização.
Ian1971 17/03

4

Então, acabei adotando uma abordagem um pouco diferente. Segui as etapas de Dan na etapa 3, mas adicionei outro arquivo: App.Base.Config. Este arquivo contém as definições de configuração que você deseja em todos os App.Config gerados. Então eu uso o BeforeBuild (com a adição de Yuri no TransformXml) para transformar a configuração atual com a configuração Base no App.config. O processo de compilação usa o App.config transformado normalmente. No entanto, um aborrecimento é que você deseja excluir o App.config em constante mudança do controle de origem posteriormente, mas os outros arquivos de configuração agora dependem dele.

  <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

Apenas um pequeno aprimoramento da solução que parece estar publicada em todos os lugares agora:

<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
  • isto é, a menos que você planeje ficar com sua versão atual do VS para sempre

Você pode explicar por favor responder um pouco ou fornecer fontes para explicá-lo?
roydukkey

4
Não parece $(VisualStudioVersion)estar definido ao usar o MSBuild diretamente.
21413 Jeremy Smith

Este deve ser um comentário a stackoverflow.com/a/5109530/2003763 (I acabou de adicionar a mesma informação como um comentário lá)
Thibault D.

2

Criei outra alternativa à publicada por Vishal Joshi, na qual o requisito de alterar a ação de compilação para Conteúdo foi removido e também implementei o suporte básico para a implantação do ClickOnce. Eu digo básico, porque não o testei completamente, mas deve funcionar no cenário típico de implantação do ClickOnce.

A solução consiste em um único projeto MSBuild que uma vez importado para um projeto de aplicativo do Windows existente (* .csproj) estende o processo de compilação para contemplar a transformação app.config.

Você pode ler uma explicação mais detalhada no Visual Studio App.config XML Transformation e o arquivo de projeto MSBuild pode ser baixado do GitHub .


1

Se você usa um TFS online (versão em nuvem) e deseja transformar o App.Config em um projeto, pode fazer o seguinte sem instalar nenhuma ferramenta extra. No VS => Descarregar o projeto => Editar arquivo do projeto => Vá para a parte inferior do arquivo e adicione o seguinte:

<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 e Destination funciona para uso local e servidor TFS online (Cloud).


0

A solução proposta não funcionará quando uma biblioteca de classes com o arquivo de configuração for referenciada em outro projeto (no meu caso, era a biblioteca de projetos do trabalhador do Azure). Ele não copiará o arquivo transformado correto da objpasta para a bin\##configuration-name##pasta. Para fazê-lo funcionar com alterações mínimas, você precisa alterar o AfterCompiledestino para BeforeCompile:

<Target Name="BeforeCompile" Condition="exists('app.$(Configuration).config')">
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.