web-dev-qa-db-fra.com

Transformation App.Config pour des projets qui ne sont pas des projets Web dans Visual Studio?

Pour les applications Web Visual Studio 2010, nous disposons des fonctionnalités de transformation de configuration grâce auxquelles nous pouvons gérer plusieurs fichiers de configuration pour différents environnements. Toutefois, la même fonctionnalité n'est pas disponible pour les fichiers App.Config pour Windows Services/WinForms ou l'application console.

Il existe une solution de contournement disponible, comme suggéré ici: Application de la magie XDT à App.Config .

Cependant, ce n'est pas simple et nécessite un certain nombre d'étapes. Existe-t-il un moyen plus simple d’atteindre le même résultat pour les fichiers app.config?

518
Amitabh

Ceci fonctionne maintenant avec l’add-in Visual Studio traité dans cet article: Syntaxe de transformation de SlowCheetah - Web.config maintenant généralisée pour n’importe quel fichier de configuration XML .

Vous pouvez cliquer avec le bouton droit sur votre web.config et cliquer sur "Ajouter des transformations de configuration". Lorsque vous faites cela, vous obtenez un web.debug.config et un web.release.config. Si vous le souhaitez, vous pouvez créer un fichier web.w Whatever.config, à condition que le nom soit aligné avec un profil de configuration. Ces fichiers ne sont que les modifications que vous souhaitez apporter, pas une copie complète de votre fichier web.config.

Vous pourriez penser que vous voudriez utiliser XSLT pour transformer un fichier web.config, mais bien qu'ils se sentent intuitivement corrects, ils sont en réalité très verbeux.

Voici deux transformations, une en utilisant XSLT et la même en utilisant la syntaxe/l'espace de nom de la transformation du document XML. Comme pour toutes les choses, XSLT peut être utilisé de différentes manières, mais vous avez une idée générale. XSLT est un langage de transformation d'arbre généralisé, tandis que ce déploiement est optimisé pour un sous-ensemble spécifique de scénarios courants. Mais la partie intéressante est que chaque transformation XDT est un plugin .NET, vous pouvez donc créer le vôtre.

<?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 la même chose via la transformation de déploiement:

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

J'ai essayé plusieurs solutions et voici la plus simple que j'ai personnellement trouvée.
Dan a souligné dans les commentaires que le message d'origine appartient à Oleg Sych - merci, Oleg!

Voici les instructions:

1. Ajoutez un fichier XML pour chaque configuration dans le projet.

En règle générale, vous aurez les configurations Debug et Release afin de nommer vos fichiers App.Debug.config et App.Release.config. Dans mon projet, j'ai créé une configuration pour chaque type d'environnement. Vous voudrez peut-être expérimenter avec cela.

2. Décharger le projet et ouvrir le fichier .csproj pour le modifier

Visual Studio vous permet d'éditer . Csproj des fichiers directement dans l'éditeur - il vous suffit de décharger le projet au préalable. Cliquez ensuite dessus avec le bouton droit de la souris et sélectionnez Éditez <NomProjet> .csproj .

3. Lier les fichiers App. *. Config au fichier App.config principal

Recherchez la section de fichier de projet contenant toutes les références App.config et App.*.config. Vous remarquerez que leurs actions de construction sont définies sur None:

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

Tout d’abord, définissez l’action de construction pour tous sur Content.
Ensuite, assurez-vous que tous les fichiers propres à la configuration sont dépendants du App.config principal de Visual Studio. les regroupe comme il le fait pour les fichiers concepteur et code-behind.

Remplacez XML ci-dessus par celui ci-dessous:

<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. Activer la magie des transformations

En fin de fichier après

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

et avant la finale

</Project>

insérez le XML suivant:

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

Vous pouvez maintenant recharger le projet, le construire et profiter des transformations App.config!

FYI

Assurez-vous que vos fichiers App.*.config ont la bonne configuration, comme ceci:

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

Une autre solution que j'ai trouvée consiste à NE PAS utiliser les transformations, mais simplement disposer d'un fichier de configuration séparé, par exemple. app.Release.config. Ajoutez ensuite cette ligne à votre fichier csproj.

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

Cela générera non seulement le fichier correct myprogram.exe.config, mais si vous utilisez le projet de configuration et de déploiement dans Visual Studio pour générer MSI, le projet de déploiement sera forcé à utiliser le fichier de configuration correct lors de la création du package.

127
Alec

D'après mon expérience, les éléments dont j'ai besoin pour rendre l'environnement spécifique sont des éléments tels que les chaînes de connexion, les paramètres d'application et les paramètres souvent smpt. Le système de configuration permet de spécifier ces choses dans des fichiers séparés. Vous pouvez donc utiliser ceci dans votre app.config/web.config:

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

Ce que je fais généralement est de placer ces sections spécifiques à la configuration dans des fichiers séparés, dans un sous-dossier appelé ConfigFiles (dans la racine de la solution ou au niveau du projet, cela dépend). Je définis un fichier par configuration, par exemple. smtp.config.Debug et smtp.config.Release.

Ensuite, vous pouvez définir un événement de pré-construction comme suit:

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

Dans le développement d'une équipe, vous pouvez affiner ce paramètre en incluant le% COMPUTERNAME% et/ou% USERNAME% dans la convention.

Bien entendu, cela implique que les fichiers cibles (x.config) ne doivent PAS être placés dans le contrôle de code source (car ils sont générés). Vous devez néanmoins les ajouter au fichier de projet et définir leur propriété de type de sortie sur "Copier toujours" ou "Copier si plus récent".

Simple, extensible, et cela fonctionne pour tous les types de projets Visual Studio (console, winforms, wpf, web).

33
jeroenh

Inspiré par Oleg et d'autres dans cette question, j'ai pris la solution https://stackoverflow.com/a/5109530/2286801 un pas de plus pour activer les éléments suivants.

  • Fonctionne avec ClickOnce
  • Fonctionne avec les projets d'installation et de déploiement dans VS 2010
  • Fonctionne avec VS2010, 2013, 2015 (n'a pas testé 2012 mais devrait également fonctionner).
  • Fonctionne avec Team Build. (Vous devez installer soit A) Visual Studio ou B) Microsoft.Web.Publishing.targets et Microsoft.Web.Publishing.Tasks.dll.

Cette solution fonctionne en effectuant la transformation app.config avant que le fichier app.config soit référencé pour la première fois dans le processus MSBuild. Il utilise un fichier de cibles externes pour faciliter la gestion de plusieurs projets.

Instructions:

Des étapes similaires à l'autre solution. J'ai cité ce qui reste identique et je l'ai inclus pour une complétude et une comparaison plus facile.

0. Ajoutez un nouveau fichier à votre projet appelé 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. Ajoutez un fichier XML pour chaque configuration dans le projet.

En règle générale, vous aurez les configurations Debug et Release afin de nommer vos fichiers App.Debug.config et App.Release.config. Dans mon projet, j’ai créé une configuration pour chaque type d’énironnement, de sorte que vous voudrez peut-être expérimenter avec cela.

2. Décharger le projet et ouvrir le fichier .csproj pour le modifier

Visual Studio vous permet d’éditer .csproj directement dans l’éditeur - il vous suffit de décharger le projet au préalable. Cliquez ensuite dessus avec le bouton droit de la souris et sélectionnez Modifier .csproj.

3. Lier les fichiers App. *. Config au fichier App.config principal

Recherchez la section de fichier de projet contenant toutes les références App.config et App. *. Config et remplacez-la comme suit. Vous remarquerez que nous utilisons Aucun au lieu de Contenu.

<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. Activer la magie des transformations

En fin de fichier après

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

et avant la finale

</Project>

insérez le XML suivant:

<Import Project="AppConfigTransformation.targets" />

Terminé!

28
bdeem

Vous pouvez utiliser un fichier de configuration distinct par configuration, par exemple. app.Debug.config, app.Release.config, puis utilisez la variable de configuration dans votre fichier de projet:

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

Cela créera ensuite le fichier ProjectName.exe.config approprié en fonction de la configuration que vous construisez.

27
Tevin

J'ai écrit l'extension Nice pour automatiser la transformation app.config comme celle intégrée dans Web Application Project Configuration Transform

Le principal avantage de cette extension est que vous n’avez pas besoin de l’installer sur toutes les machines construites.

13
Golan Avraham

J'ai donc adopté une approche légèrement différente. J'ai suivi les étapes de Dan jusqu'à l'étape 3, mais j'ai ajouté un autre fichier: App.Base.Config. Ce fichier contient les paramètres de configuration souhaités dans chaque App.Config généré. Ensuite, j'utilise BeforeBuild (avec l'ajout de Yuri à TransformXml) pour transformer la configuration actuelle avec la configuration de base en App.config. Le processus de construction utilise ensuite le fichier App.config transformé normalement. Cependant, vous voudrez peut-être par la suite exclure du contrôle de code le fichier App.config, qui change constamment, mais les autres fichiers de configuration en dépendent désormais.

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

Installez "Configuration Transform Tool" dans Visual Studio à partir de Marketplace et redémarrez VS. Vous pourrez également voir la prévisualisation du menu pour app.config.

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

4
Agnel Amodia

Je résous ce problème avec cet outil http://ctt.codeplex.com/ . Je l'utilise avec le script CCNet/nAnt pour créer des packages.

3
outcoldman

Juste une petite amélioration à la solution qui semble être affichée partout maintenant:

<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
  • c'est-à-dire, sauf si vous envisagez de rester pour toujours avec votre version actuelle de VS
3
Yuri Makassiouk

J'ai créé une autre alternative à celle publiée par Vishal Joshi, où il est nécessaire de modifier l'action de construction en Content est supprimé et implémente également le support de base pour le déploiement de ClickOnce. Je dis basique, car je ne l'ai pas testé minutieusement, mais cela devrait fonctionner dans le scénario de déploiement typique de ClickOnce.

La solution consiste en un seul projet MSBuild qui, une fois importé dans un projet d'application Windows existant (* .csproj), étend le processus de génération pour envisager une transformation app.config.

Vous pouvez lire une explication plus détaillée sur Transformation XML de Visual Studio App.config et le fichier de projet MSBuild peut être téléchargé de GitHub .

2
João Angelo

Si vous utilisez un TFS en ligne (version Cloud) et que vous souhaitez transformer App.Config dans un projet, vous pouvez procéder comme suit sans installer aucun outil supplémentaire. De VS => Déchargez le projet => Éditer le fichier de projet => Allez au bas du fichier et ajoutez ce qui suit:

<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 and Destination fonctionne pour une utilisation locale et un serveur TFS en ligne (Cloud).

1
Benjamin

la solution proposée ne fonctionnera pas si une bibliothèque de classes avec un fichier de configuration est référencée à partir d'un autre projet (dans mon cas, il s'agissait de la bibliothèque de projets de travail Azure). Il ne copiera pas le fichier transformé correct du dossier obj dans le dossier bin\##configuration-name##. Pour que cela fonctionne avec des modifications minimes, vous devez remplacer AfterCompile target par BeforeCompile:

<Target Name="BeforeCompile" Condition="exists('app.$(Configuration).config')">
0
avs099