Cómo seleccionar diferentes app.config para varias configuraciones de compilación

115

Tengo un proyecto de tipo dll que contiene pruebas de integración de MSTest. En mi máquina pasan las pruebas y quiero que suceda lo mismo en un servidor CI (yo uso TeamCity). Pero las pruebas fallan, porque necesito modificar algunas configuraciones en app.config. Es por eso que estaba pensando en tener un segundo archivo app.config separado que contendrá la configuración del servidor CI.

Entonces me gustaría tener

/ Sln
 / Proyecto
  app.config (creo que VS lo requiere)
  app.Release.config (Este es un archivo de configuración independiente e independiente)

Por lo tanto, si selecciono la configuración de lanzamiento en la configuración de compilación en CI, me gustaría usar el archivo app.Release.config en lugar de app.config

Problema
Esto no parece ser sencillo para proyectos simples de tipo .dll. Para proyectos web, puedo hacer transformaciones de configuración web. Encontré un truco sobre cómo hacer estas transformaciones para un proyecto de tipo dll, pero no soy un gran fanático de los trucos.

Pregunta
¿Cuál es un enfoque estándar para modificar los archivos app.config dependiendo de la configuración de compilación para proyectos .NET (como Debug, Release, ...)?

oleksii
fuente

Respuestas:

154

Utilice el complemento SlowCheetah . Para más opciones y detalles sobre cómo usar SlowCheetah, siga leyendo.

Como ya habrá notado, no existe una forma predeterminada y fácil de usar diferentes archivos de configuración para un proyecto de tipo Biblioteca (.dll) . La razón es que el pensamiento actual es: "¡No es necesario"! Los desarrolladores de framework estiman que necesita configuración para el archivo ejecutable: ya sea una consola, escritorio, web, aplicación móvil u otra cosa. Si comienza a proporcionar la configuración para una dll , puede terminar con algo que puedo llamar un infierno de configuración . Es posible que ya no entienda (fácilmente) por qué esta y aquella variables tienen valores tan extraños que aparentemente vienen de la nada.

"Espera", puedes decir, "pero necesito esto para mi integración / prueba unitaria, ¡y es una biblioteca!". Y eso es cierto y esto es lo que puede hacer (elija solo uno, no mezcle):

1. SlowCheetah: transforma el archivo de configuración actual

Puede instalar SlowCheetah , un complemento de Visual Studio que realiza todas las modificaciones (o transformaciones) de XML de bajo nivel por usted. La forma en que funciona, brevemente:

  • Instale SlowCheetah y reinicie Visual Studio (Visual Studio> Herramientas> Extensiones y actualizaciones ...> En línea> Galería de Visual Studio> busque "Slow Cheetah")
  • Defina las configuraciones de su solución ( Debug y Release están ahí de forma predeterminada), puede agregar más (haga clic con el botón derecho en la solución en Solution Explorer > Configuration Manager ... > Active Solution Configuration > New ...
  • Agregue un archivo de configuración si es necesario
  • Haga clic derecho en el archivo de configuración> Agregar transformación
    • Esto creará archivos de transformación, uno por su configuración
    • Los archivos de transformación funcionan como inyectores / mutadores, encuentran el código XML necesario en el archivo de configuración original e inyectan nuevas líneas o mutan el valor necesario, lo que sea que le digas que haga

2. Jugar con el archivo .proj: copiar y cambiar el nombre de un archivo de configuración completamente nuevo

Tomado originalmente de aquí . Es una tarea personalizada de MSBuild que puede incrustar en el archivo .proj de Visual Studio . Copie y pegue el siguiente código en el archivo del proyecto

<Target Name="AfterBuild">
    <Delete Files="$(TargetDir)$(TargetFileName).config" />
    <Copy SourceFiles="$(ProjectDir)\Config\App.$(Configuration).config"
          DestinationFiles="$(TargetDir)$(TargetFileName).config" />
</Target>

Ahora cree una carpeta en el proyecto llamado Configy agregue nuevos archivos allí: App.Debug.config , App.Release.config , etc. Ahora, dependiendo de su configuración, Visual Studio seleccionará el archivo de configuración de una Configcarpeta y lo copiará y le cambiará el nombre en el directorio de salida. Entonces, si tenía el proyecto PatternPA.Test.Integration y una configuración de depuración seleccionada, en la carpeta de salida después de la compilación encontrará un archivo PatternPA.Test.Integration.dll.config que se copió Config\App.Debug.configy se renombró posteriormente.

Estas son algunas notas que puede dejar en los archivos de configuración

<?xml version="1.0" encoding="utf-8"?>
<configuration>

    <!-- This file is copied and renamed by the 'AfterBuild' MSBuild task -->

    <!-- Depending on the configuration the content of projectName.dll.config 
        is fully substituted by the correspondent to build configuration file 
        from the 'Config' directory. -->

</configuration>

En Visual Studio puedes tener algo como esto

Estructura del proyecto

3. Utilice archivos de secuencias de comandos fuera de Visual Studio

Cada herramienta de compilación (como NAnt , MSBuild ) proporcionará capacidades para transformar el archivo de configuración según la configuración. Esto es útil si crea su solución en una máquina de compilación, donde necesita tener más control sobre qué y cómo preparar el producto para su lanzamiento.

Por ejemplo, puede usar la tarea de publicación web dll para transformar cualquier archivo de configuración

<UsingTask AssemblyFile="..\tools\build\Microsoft.Web.Publishing.Tasks.dll"
    TaskName="TransformXml"/>

<PropertyGroup>
    <!-- Path to input config file -->  
    <TransformInputFile>path to app.config</TransformInputFile>
    <!-- Path to the transformation file -->    
    <TransformFile>path to app.$(Configuration).config</TransformFile>
    <!-- Path to outptu web config file --> 
    <TransformOutputFile>path to output project.dll.config</TransformOutputFile>
</PropertyGroup>

<Target Name="transform">
    <TransformXml Source="$(TransformInputFile)"
                  Transform="$(TransformFile)"
                  Destination="$(TransformOutputFile)" />
</Target>
oleksii
fuente
Su segunda solución funciona bien, pero no para publicar proyectos web. Después de publicar un proyecto ASP.NET, se publica el web.config original.
Massood Khaari
3
@MassoodKhaari, debe asegurarse de que se llame a esta tarea para el destino de publicación. Cuando publica un proyecto, se llama a un destino de compilación independiente, que puede no llamar de forma predeterminada AfterBuild. Durante la compilación típica, AfterBuildse llama al destino de forma predeterminada. Debería haber una solución rápida para el caso de publicación
oleksii
1
Usé su segundo método (un poco). Fui a las propiedades del proyecto y edité BeforeBuild para copiar el App.<Target>.configsobre App.configen el directorio del proyecto , no el directorio de salida.
SparK
@oleksii Tienes razón. Pero todavía no pude encontrar el destino que usa mi proceso de publicación web (en Visual Studio 2013).
Massood Khaari
1
Estoy usando el segundo método, pero necesitaba agregar una condición al objetivo de AfterBuild para asegurarme de que el archivo realmente existe antes de eliminarlo. Tengo una configuración de compilación de depuración, que básicamente solo usa el archivo App.config predeterminado, pero no tenía App.Debug.config, lo que significaba que el paso de compilación fallaría. Acabo de agregar Condition="Exists('$(ProjectDir)App.$(Configuration).config')".
Siewers
23

Puede probar el siguiente enfoque:

  1. Haga clic con el botón derecho en el proyecto en el Explorador de soluciones y seleccione Descargar proyecto .
  2. El proyecto se descargará. Vuelva a hacer clic con el botón derecho en el proyecto y seleccione Editar <YourProjectName> .csproj .
  3. Ahora puede editar el archivo del proyecto dentro de Visual Studio.
  4. Busque el lugar en el archivo * .csproj donde se incluye el archivo de configuración de su aplicación. Se verá así:
    <ItemGroup>
        <Ninguno Incluir = "App.config" />
    </ItemGroup>
  1. Reemplace estas líneas con lo siguiente:
    <ItemGroup Condition = "'$ (Configuration)' == 'Debug'">
        <Ninguno Incluye = "App.Debug.config" />
    </ItemGroup>

    <ItemGroup Condition = "'$ (Configuration)' == 'Release'">
        <Ninguno Incluye = "App.Release.config" />
    </ItemGroup>

No he probado este enfoque de app.configarchivos, pero funcionó bien con otros elementos de proyectos de Visual Studio. Puede personalizar el proceso de compilación de la forma que desee. De todos modos, avíseme el resultado.

vharavy
fuente
Tnx para la respuesta, pero esto no funciona con app.config. VS requiere una app.configconfiguración de lanzamiento obligatoria y no aplica si uso VS build o Teamcity VS sln build runner.
oleksii
2
Aquí se explica cómo hacerlo: Habilite app.debug.config app.release.config
Gabrielizalo
1
¿Por qué esta respuesta tiene tantos votos a favor? Lo probé y no funciona. De hecho, tanto en el modo de depuración como en el de lanzamiento, no hay un archivo App.config y, por lo tanto, no hay un archivo correspondiente en la carpeta de salida. Los archivos App.Debug.config y App.Release.config no tienen ningún significado para Visual Studio.
MarkusParker
No funciona: .csproj no se puede abrir, mensaje de error "los elementos fuera de los elementos de destino deben tener: Incluir, Actualizar o Eliminar"
Elo
12

Debería considerar ConfigGen . Fue desarrollado para este propósito. Produce un archivo de configuración para cada máquina de implementación, basado en un archivo de plantilla y un archivo de configuración. Sé que esto no responde específicamente a su pregunta, pero bien podría responder a su problema.

Entonces, en lugar de Debug, Release, etc., es posible que tenga Test, UAT, Production, etc. También puede tener diferentes configuraciones para cada máquina de desarrollo, de modo que pueda generar una configuración específica para su máquina de desarrollo y cambiarla sin afectar la implementación de nadie más. .

Un ejemplo de uso podría ser ...

<Target Name="BeforeBuild">
    <Exec Command="C:\Tools\cfg -s $(ProjectDir)App.Config.Settings.xls -t       
        $(ProjectDir)App.config.template.xml -o $(SolutionDir)ConfigGen" />

    <Exec Command="C:\Tools\cfg -s $(ProjectDir)App.Config.Settings.xls -t
        $(ProjectDir)App.config.template.xml -l -n $(ProjectDir)App.config" />
</Target>

Si coloca esto en su archivo .csproj y tiene los siguientes archivos ...

$(ProjectDir)App.Config.Settings.xls

MachineName        ConfigFilePath   SQLServer        

default             App.config      DEVSQL005
Test                App.config      TESTSQL005
UAT                 App.config      UATSQL005
Production          App.config      PRODSQL005
YourLocalMachine    App.config      ./SQLEXPRESS


$(ProjectDir)App.config.template.xml 

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
   <configuration>
   <appSettings>
       <add key="ConnectionString" value="Data Source=[%SQLServer%]; 
           Database=DatabaseName; Trusted_Connection=True"/>
   </appSettings>
</configuration>

... entonces este será el resultado ...

Desde el primer comando, se genera un archivo de configuración para cada entorno especificado en el archivo xls, ubicado en el directorio de salida $ (SolutionDir) ConfigGen

.../solutiondir/ConfigGen/Production/App.config

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
   <configuration>
   <appSettings>
       <add key="ConnectionString" value="Data Source=PRODSQL005; 
           Database=DatabaseName; Trusted_Connection=True"/>
   </appSettings>
</configuration>

Desde el segundo comando, el App.config local usado en su máquina de desarrollo será reemplazado por la configuración generada especificada por el conmutador local (-l) y el conmutador de nombre de archivo (-n).

Daniel Dyson
fuente
2
Tnx por la respuesta, esto no se ve mal. Pero hay algunos inconvenientes, muestra solo 75 descargas (por lo tanto, no está maduro) y funciona solo con .xls o .xlsx. Realmente no quiero depender de otro formato de documento personalizado para operaciones simples. Estaba buscando un enfoque más estándar ...
oleksii
2
Punto justo, aunque dice 194 descargas en CodePlex, xls es una hoja de cálculo, apenas un formato personalizado, y conozco tres bancos de inversión principales que han aprobado este uso, así que si es lo suficientemente bueno para ellos ... Además, uno de las funciones solicitadas actualmente es utilizar xml para la configuración. Está casi listo, pero de todos modos prefiero el enfoque de hoja de cálculo. Es mucho más fácil ver todas las configuraciones para cada entorno en una vista tabular
Daniel Dyson
Ahora estamos en las etapas finales de prueba de una versión de configGen que se puede usar para generar archivos de texto sin formato, no solo xml. Entonces, si desea generar css, sql, javascript, etc. específicos del entorno, esté atento al sitio configGen
Daniel Dyson
gracias Daniel por la solución, esto es exactamente lo que estaba buscando. Voy a darle una oportunidad.
Bhupinder Singh
10

Utilizando el mismo enfoque que Romeo, lo adapté a Visual Studio 2010:

 <None Condition=" '$(Configuration)' == 'Debug' " Include="appDebug\App.config" />

 <None Condition=" '$(Configuration)' == 'Release' " Include="appRelease\App.config" />

Aquí debe mantener ambos archivos App.config en diferentes directorios (appDebug y appRelease). ¡Lo probé y funciona bien!

tem peru
fuente
3

Estoy usando la herramienta XmlPreprocess para la manipulación de archivos de configuración. Está utilizando un archivo de mapeo para múltiples entornos (o múltiples objetivos de compilación en su caso). Puede editar el archivo de mapeo por Excel. Es muy fácil de usar.

Ludwo
fuente
3

SlowCheetah y FastKoala de VisualStudio Gallery parecen ser muy buenas herramientas que ayudan con este problema.

Sin embargo, si desea evitar los complementos o utilizar los principios que implementan de manera más extensa a lo largo de sus procesos de compilación / integración, agregar esto a sus archivos msbuild * proj es una solución abreviada.

Nota: esto es más o menos una reelaboración del número 2 de la respuesta de @ oleksii.

Esto funciona para proyectos .exe y .dll:

  <Target Name="TransformOnBuild" BeforeTargets="PrepareForBuild">
    <TransformXml Source="App_Config\app.Base.config" Transform="App_Config\app.$(Configuration).config" Destination="app.config" />
  </Target>

Esto funciona para proyectos web:

  <Target Name="TransformOnBuild" BeforeTargets="PrepareForBuild">
    <TransformXml Source="App_Config\Web.Base.config" Transform="App_Config\Web.$(Configuration).config" Destination="Web.config" />
  </Target>

Tenga en cuenta que este paso ocurre incluso antes de que comience la compilación adecuada. La transformación del archivo de configuración ocurre en la carpeta del proyecto. Para que el web.config transformado esté disponible cuando esté depurando (un inconveniente de SlowCheetah).

Recuerde que si crea la carpeta App_Config (o como elija llamarla), los distintos archivos de configuración intermedios deben tener una Acción de compilación = Ninguna y Copiar en el directorio de salida = No copiar.

Esto combina ambas opciones en un bloque. El apropiado se ejecuta en base a condiciones. Sin embargo, la tarea TransformXml se define primero:

<Project>
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="TransformOnBuild" BeforeTargets="PrepareForBuild">
    <TransformXml Condition="Exists('App_Config\app.Base.config')" Source="App_Config\app.Base.config" Transform="App_Config\app.$(Configuration).config" Destination="app.config" />
    <TransformXml Condition="Exists('App_Config\Web.Base.config')" Source="App_Config\Web.Base.config" Transform="App_Config\Web.$(Configuration).config" Destination="Web.config" />
</Target>

Eniola
fuente
Intenté esto en Visual Studio 2017 y no funciona. Disparar. Realmente esperaba que funcionara, porque parece el más fácil de implementar.
Greg Burghardt
La tarea TransformXml no está definida en los ejemplos. Estoy agregando una entrada. Puede definirlo en un archivo mycustom.targets que se incluye en todos sus proyectos de lanzamiento en su solución.
Eniola
@GregBurghardt, ¿quieres probarlo ahora?
Eniola
Podría intentarlo. Instalé el complemento Config Transform para Visual Studio, y funcionó muy bien. De hecho, me pregunto si el complemento básicamente hace lo que hace su respuesta.
Greg Burghardt
Bien, déjame saber cómo te va.
Eniola
1

Vea si el motor de transformación XDT (web.config) puede ayudarlo. Actualmente solo es compatible de forma nativa para proyectos web, pero técnicamente no hay nada que le impida usarlo en otros tipos de aplicaciones. Hay muchas guías sobre cómo usar XDT editando manualmente los archivos del proyecto, pero encontré un complemento que funciona muy bien: https://visualstudiogallery.msdn.microsoft.com/579d3a78-3bdd-497c-bc21-aa6e6abbc859

El complemento solo ayuda a configurar la configuración, no es necesario compilar y la solución se puede compilar en otras máquinas o en un servidor de compilación sin que se requiera el complemento ni ninguna otra herramienta.

TGasdf
fuente
Esta debería ser la respuesta ahora. Lo probé en VS 2017 y funciona como un encanto. No es necesario publicar el proyecto. Solo constrúyelo. Funciona muy bien para nuestro proyecto de prueba para su uso en nuestra compilación de integración continua para que podamos ejecutar pruebas de Selenium en modo sin cabeza, pero se ejecutan localmente con el navegador abierto. +1.000.000 si pudiera.
Greg Burghardt
1

He resuelto este tema con la solución que encontré aquí: http://www.blackwasp.co.uk/SwitchConfig.aspx

En resumen, lo que dicen es: "agregando un evento posterior a la compilación. [...] Necesitamos agregar lo siguiente:

if "Debug"=="$(ConfigurationName)" goto :nocopy
del "$(TargetPath).config"
copy "$(ProjectDir)\Release.config" "$(TargetPath).config"
:nocopy
Janbro
fuente
¡Con mucho, el método más fácil para hacer lo que debería haber sido una función muy simple y esencial que fue arruinada por los pensadores! Gracias Janbro.
BoiseBaked
1

Escuché cosas buenas sobre SlowCheetah, pero no pude hacerlo funcionar. Hice lo siguiente: agregue la etiqueta am a cada uno para una configuración específica.

Ex:

<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'UAT|AnyCPU'">
    <OutputPath>bin\UAT\</OutputPath>
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <AppConfig>App.UAT.config</AppConfig>
  </PropertyGroup>
Miguel
fuente
Esta parece otra forma muy sencilla de cambiar los archivos app.config según la configuración de compilación. Mike, ¿probaste con las configuraciones estándar de depuración y versión?
BoiseBaked
0

Después de investigar un poco sobre la administración de configuraciones para desarrollo y compilaciones, etc., decidí lanzar la mía propia, la he puesto a disposición en bitbucket en: https://bitbucket.org/brightertools/contemplate/wiki/Home

Estos múltiples archivos de configuración para múltiples entornos, es una herramienta de reemplazo de entrada de configuración básica que funcionará con cualquier formato de archivo basado en texto.

Espero que esto ayude.

Mark Redman
fuente