[Deploy] Trasformaciones de config (II): App.config

Siguiendo con la temática del artículo anterior en el que se mostró cómo crear configuraciones y como aplicar los valores en el web.config para cada una de ellas, en esta ocasión dedicaré el asunto a App.config

¿Por qué lo visto anteriormente no es válido? Técnicamente es válido, pero el problema es que por defecto los app.config no están pensados para soportar transformaciones y los proyectos en los que se encuentran, tradicionalmente de consola o aplicaciones de escritorio, no tienen en cuenta este detalle.

Si se crea un proyecto de consola o aplicación de escritorio en general se aprecia que el app.config no dispone de versión para Debug y Release, pese a que dichas configuraciones sí existen en el proyecto o solución. Por lo tanto, lo primero que se debe hacer es habilitar tantos app.config como configuraciones se disponen.

Como resumen breve, en el post anterior se comenta lo siguiente:

  • Por un lado, las distintas versiones de web.config son en realidad desde el punto de vista del proyecto ficheros dependientes de otro.
  • Por otro lado, para poder habilitar las transformaciones es necesario añadir el import correspondiente.

Crear los app.config

Respecto al primer punto la principal diferencia es que debemos crear los ficheros de forma manual, puesto que no tenemos menú disponible para ello. Así pues, si se dispone de la misma configuración que el artículo anterior de cuatro entornos (dev, qa, pre y pro) se creará en primer lugar los app.config equivalentes:

Además cada fichero de configuración se ha creado con una estructura básica por defecto que deberemos preparar. Mientras que la parte original permanece así:

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

<configuration>

</configuration>

Se debe añadir el namespace de transformaciones:

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

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">

</configuration>

Por lo tanto la estructura de ficheros que queda en el proyecto sería algo muy parecido a esto:

image

Para que los ficheros pemanezcan jerarquizados en base al App.config original, se debe modificar el csproj indicando que el resto de ficheros que hemos creado por entorno tienen son dependientes del App.config “padre”:

<ItemGroup>

  <None Include="App.config" />

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

    <DependentUpon>App.config</DependentUpon>

  </None>

  <None Include="App.PRE.config">

    <DependentUpon>App.config</DependentUpon>

  </None>

  <None Include="App.QA.config">

    <DependentUpon>App.config</DependentUpon>

  </None>

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

    <DependentUpon>App.config</DependentUpon>

  </None>

</ItemGroup>

De este modo ya se dispone de un app.config jerárquico al igual que ocurre en un proyecto web:

image

Trasformación de app.config

Ahora se debe importar la capacidad de transformar el XML. Fácilmente se puede lograr añadiendo la siguiente línea en el csproj:

<Import Project="$(MSBuildExtensionsPath)MicrosoftVisualStudiov12.0WebMicrosoft.Web.Publishing.targets" />

Ahora podemos modificar el web.config y añadir algo en función del entorno. A modo de ejemplo mantengo el del artículo anterior, por lo que el web.config original quedaría de la siguiente forma:

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

<configuration>

  <appSettings>

    <add key="environmentName" value="none"/>

  </appSettings>

    <startup> 

        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />

    </startup>

</configuration>

Y el de QA así:

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

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">

  <appSettings>

    <add key="environmentName" value="QA"

         xdt:Transform="Replace"

         xdt:Locator="Match(key)"/>

  </appSettings>

</configuration>

Si compilamos en QA, se aprecia que no ha aplicado ningún tipo de transfomación y mantiene el web.config original. Aquí tenemos dos problemas:

  • El proyecto de consola no entiende de transformaciones, somos nosotros quienes las estamos introduciendo casi “a calzador”.
  • No disponemos de publicación condicionada. En un proyecto web se puede establecer multitud de parámetros que se tienen en cuenta a la hora de publicar, entro ellos la configuración del entorno. Aquí directamente se ofrece la posiblidad de publicar con la única opción de indicar la ruta donde se copiará el resultado de la compilación que en esta opción será siempre Release.

Por lo tanto, lo que se debe hacer es habilitar que tenga en cuenta en la compilación el resto de entornos personalizados que se han ido creando. Para ello se necesita añadir al csproj la siguiente opción post-compilación:

<Target Name="AfterBuild">

  <TransformXml 

    Source="@(AppConfigWithTargetPath)" 

    Transform="App.$(ConfigurationName).config" 

    Destination="@(AppConfigWithTargetPath->'$(OutDir)%(TargetPath)')" />

</Target>

Se añade TransformXML gracias al soporte del Import de Web.Transformation y se transformará todo fichero App.{Entorno}.config. La variable $(ConfigurationName) es una macro predefinida de msbuild que indica cuál es el nombre de la configuración que actualmente está seleccionada. Como se ha seguido el patrón de generar la configuración por entorno (app.debug.config, app.qa.config, etc) podrá encontrar el fichero y de este modo aplicará la transformación. Es decir, gracias a esta tarea de post-compilación se comprobará el efecto de la transformación al compilar el proyecto independientemente o no de la publicación del mismo, justo al contrario que en un proyecto web. Finalmente el app.config para QA quedaría del siguiente modo:

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

<configuration>

  <appSettings>

    <add key="environmentName" value="QA"/>

  </appSettings>

    <startup> 

        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />

    </startup>

</configuration>

 

Opciones de terceros

Existen estas opciones en lugar de aplicar el DIY:

  • Configuration Transform: Es una extensión de VS(2010,2012,2013 por ahora) que añade la funcionalidad que aquí se ha aplicado de forma manual.
  • SlowCheetah: No he llegado a usarlo pero parece ser que está descontinuado. Hace un año o dos era una buena solución para la gestión de XML en configuraciones.

Fuente:

Basado en esta respuesta de Stackoverflow y experiencias varias

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *