Comment sélectionner différents app.config pour plusieurs configurations de build

115

J'ai un projet de type dll qui contient des tests d'intégration MSTest. Sur ma machine, les tests réussissent et je veux que la même chose se produise sur un serveur CI (j'utilise TeamCity). Mais les tests échouent, car je dois modifier certains paramètres dans app.config. C'est pourquoi je pensais avoir un deuxième fichier app.config distinct qui contiendra les paramètres du serveur CI.

Alors j'aimerais avoir

/ Sln
 / Proj
  app.config (je pense que cela est requis par VS)
  app.Release.config (Ceci est un fichier de configuration indépendant et autonome)

Ainsi, si je sélectionne la configuration de version dans la configuration de construction sur CI, je voudrais utiliser le fichier app.Release.config au lieu de app.config

Problème
Cela ne semble pas simple pour les projets de type .dll simples. Pour les projets Web, je peux effectuer des transformations de configuration Web. J'ai trouvé un hack comment faire ces transformations pour un projet de type dll, mais je ne suis pas un grand fan de hacks.

Question
Quelle est une approche standard pour modifier les fichiers app.config en fonction de la configuration de build pour les projets .NET (tels que Debug, Release, ...)?

oleksii
la source

Réponses:

154

Utilisez le plugin SlowCheetah . Pour plus d'options et de détails sur l'utilisation de SlowCheetah, continuez à lire.

Comme vous l'avez déjà remarqué, il n'existe aucun moyen simple et par défaut d'utiliser différents fichiers de configuration pour un projet de type Bibliothèque (.dll) . La raison en est que la pensée actuelle est: "Vous n'avez pas besoin de"! Les développeurs de framework estiment que vous avez besoin d'une configuration pour le fichier exécutable: qu'il s'agisse d'une console, d'un bureau, d'un site Web, d'une application mobile ou autre. Si vous commencez à fournir la configuration d'une dll , vous pouvez vous retrouver avec quelque chose que je peux appeler un enfer de configuration . Vous ne comprenez peut-être plus (facilement) pourquoi telle ou telle variable a des valeurs aussi étranges venant de nulle part.

"Attendez", - vous pouvez dire, "mais j'en ai besoin pour mon intégration / test unitaire, et c'est une bibliothèque!". Et c'est vrai et c'est ce que vous pouvez faire (n'en choisissez qu'un, ne mélangez pas):

1. SlowCheetah - transforme le fichier de configuration actuel

Vous pouvez installer SlowCheetah - un plug-in Visual Studio qui effectue tout le pokage (ou la transformation) XML de bas niveau pour vous. La façon dont cela fonctionne, brièvement:

  • Installez SlowCheetah et redémarrez Visual Studio (Visual Studio> Outils> Extensions et mises à jour ...> En ligne> Galerie Visual Studio> recherchez «Slow Cheetah»)
  • Définissez vos configurations de solution (le débogage et la version sont là par défaut), vous pouvez en ajouter plus (clic droit sur la solution dans Explorateur de solutions > Gestionnaire de configuration ... > Configuration de la solution active > Nouveau ...
  • Ajoutez un fichier de configuration si nécessaire
  • Faites un clic droit sur le fichier de configuration> Ajouter une transformation
    • Cela créera des fichiers de transformation - un pour votre configuration
    • Les fichiers de transformation fonctionnent comme des injecteurs / mutateurs, ils trouvent le code XML nécessaire dans le fichier de configuration d'origine et injectent de nouvelles lignes ou modifient la valeur nécessaire, quoi que vous lui disiez de faire

2. Fiddle with .proj file - copie-renomme un tout nouveau fichier de configuration

À l'origine pris d' ici . Il s'agit d'une tâche MSBuild personnalisée que vous pouvez incorporer dans le fichier .proj de Visual Studio . Copiez et collez le code suivant dans le fichier projet

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

Créez maintenant un dossier dans le projet appelé Configet ajoutez-y de nouveaux fichiers: App.Debug.config , App.Release.config et ainsi de suite. À présent, en fonction de votre configuration, Visual Studio choisit le fichier de configuration dans un Configdossier et le renomme par copie dans le répertoire de sortie. Donc, si vous aviez sélectionné le projet PatternPA.Test.Integration et une configuration Debug , dans le dossier de sortie après la construction, vous trouverez un fichier PatternPA.Test.Integration.dll.config qui a été copié Config\App.Debug.configet renommé par la suite.

Voici quelques notes que vous pouvez laisser dans les fichiers de configuration

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

Dans Visual Studio, vous pouvez avoir quelque chose comme ça

Structure du projet

3. Utilisez des fichiers de script en dehors de Visual Studio

Chaque outil de construction (comme NAnt , MSBuild ) fournira des capacités pour transformer le fichier de configuration en fonction de la configuration. Cela est utile si vous créez votre solution sur une machine de génération, où vous devez avoir plus de contrôle sur quoi et comment vous préparez le produit pour la publication.

Par exemple, vous pouvez utiliser la tâche de la dll de publication Web pour transformer n'importe quel fichier de configuration

<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
la source
Votre deuxième solution fonctionne bien, mais pas pour la publication de projets Web. Après avoir publié un projet ASP.NET, le web.config d'origine est publié.
Massood Khaari
3
@MassoodKhaari vous devez vous assurer que cette tâche est appelée pour la cible de publication. Lorsque vous publiez un projet, une cible de construction distincte est appelée, qui peut ne pas appeler par défaut la AfterBuildcible. Lors de la compilation typique, la AfterBuildcible est appelée par défaut. Il devrait y avoir une solution rapide pour le cas de publication
oleksii
1
Utilisé votre deuxième méthode (un peu). Je suis allé aux propriétés du projet et j'ai édité le BeforeBuild pour copier le App.<Target>.configsur le App.configdans le répertoire du projet , pas le répertoire de sortie.
SparK
@oleksii Vous avez raison. Mais je ne pouvais toujours pas trouver la cible utilisée par mon processus de publication Web (dans Visual Studio 2013).
Massood Khaari
1
J'utilise la deuxième méthode, mais je devais ajouter une condition à la cible AfterBuild pour m'assurer que le fichier existe réellement avant de le supprimer. J'ai une configuration de construction Debug, qui utilise simplement le fichier App.config par défaut, mais je n'avais pas App.Debug.config, ce qui signifiait que l'étape de construction échouerait. Je viens d'ajouter Condition="Exists('$(ProjectDir)App.$(Configuration).config')".
Siewers le
23

Vous pouvez essayer l'approche suivante:

  1. Cliquez avec le bouton droit sur le projet dans l'Explorateur de solutions et sélectionnez Décharger le projet .
  2. Le projet sera déchargé. Cliquez à nouveau avec le bouton droit sur le projet et sélectionnez Modifier <VotreNomProjet> .csproj .
  3. Vous pouvez maintenant modifier le fichier de projet dans Visual Studio.
  4. Localisez l'emplacement dans le fichier * .csproj où votre fichier de configuration d'application est inclus. Cela ressemblera à:
    <ItemGroup>
        <None Include = "App.config" />
    </ItemGroup>
  1. Remplacez ces lignes par les suivantes:
    <ItemGroup Condition = "'$ (Configuration)' == 'Debug'">
        <None Include = "App.Debug.config" />
    </ItemGroup>

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

Je n'ai pas essayé cette approche des app.configfichiers, mais cela fonctionnait bien avec d'autres éléments de projets Visual Studio. Vous pouvez personnaliser le processus de construction de presque toutes les manières que vous souhaitez. Quoi qu'il en soit, faites-moi savoir le résultat.

vharavy
la source
Tnx pour la réponse, mais cela ne fonctionne pas avec app.config. VS nécessite une app.configconfiguration obligatoire et n'applique pas la configuration de version si j'utilise VS build ou Teamcity VS sln build runner.
oleksii
2
Voici comment faire: Activer app.debug.config app.release.config
Gabrielizalo
1
Pourquoi cette réponse a-t-elle autant de votes? Je l'ai essayé et ça ne marche pas. En fait, à la fois en mode débogage et en mode version, il n'y a pas de fichier App.config et par conséquent, il n'y a pas de fichier correspondant dans le dossier de sortie. Les fichiers App.Debug.config et App.Release.config n'ont aucune signification pour Visual Studio.
MarkusParker
Cela ne fonctionne pas: .csproj ne peut pas être ouvert, message d'erreur "les éléments en dehors des éléments cibles doivent avoir: Inclure, Mettre à jour ou Supprimer"
Elo
12

Vous devriez envisager ConfigGen . Il a été développé à cet effet. Il produit un fichier de configuration pour chaque machine de déploiement, basé sur un fichier modèle et un fichier de paramètres. Je sais que cela ne répond pas spécifiquement à votre question, mais cela pourrait bien répondre à votre problème.

Ainsi, plutôt que Debug, Release, etc., vous pouvez avoir Test, UAT, Production, etc. .

Un exemple d'utilisation pourrait être ...

<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 vous placez ceci dans votre fichier .csproj et que vous disposez des fichiers suivants ...

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

... alors ce sera le résultat ...

A partir de la première commande, un fichier de configuration généré pour chaque environnement spécifié dans le fichier xls, placé dans le répertoire de sortie $ (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>

À partir de la deuxième commande, le App.config local utilisé sur votre machine de développement sera remplacé par la configuration générée spécifiée par le commutateur local (-l) et le commutateur de nom de fichier (-n).

Daniel Dyson
la source
2
Tnx pour la réponse, cela ne semble pas mal. Mais il y a quelques inconvénients, il ne montre que 75 téléchargements (donc ce n'est pas mature) et il ne fonctionne qu'avec .xls ou .xlsx. Je ne veux pas vraiment dépendre d'un autre format de document personnalisé pour des opérations simples. Je cherchais une approche plus standard ...
oleksii
2
Bon point, bien qu'il dise 194 téléchargements sur CodePlex, xls est une feuille de calcul, à peine un format personnalisé, et je connais trois grandes banques d'investissement qui l'ont approuvé pour utilisation, donc si c'est assez bon pour elles ... Aussi, une des fonctionnalités actuellement demandées est d'utiliser xml pour les paramètres. Il est presque prêt, mais je préfère de toute façon l'approche de la feuille de calcul. Il est beaucoup plus facile de voir chaque paramètre pour chaque environnement dans une vue tabulaire
Daniel Dyson
Nous sommes maintenant dans les dernières étapes de test d'une version de configGen qui peut être utilisée pour générer des fichiers texte brut, pas seulement xml. Donc, si vous souhaitez générer des css, sql, javascript, etc. spécifiques à l'environnement, gardez un œil sur le site configGen
Daniel Dyson
merci Daniel pour la solution, c'est exactement ce que je cherchais. Je vais essayer.
Bhupinder Singh
10

En utilisant la même approche que Romeo, je l'ai adapté à Visual Studio 2010:

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

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

Ici, vous devez conserver les deux fichiers App.config dans différents répertoires (appDebug et appRelease). Je l'ai testé et ça marche bien!

tem pérou
la source
3

J'utilise l' outil de XmlPreprocess pour la manipulation des fichiers de configuration. Il utilise un fichier de mappage pour plusieurs environnements (ou plusieurs cibles de construction dans votre cas). Vous pouvez modifier le fichier de mappage par Excel. Il est très simple à utiliser.

Ludwo
la source
3

SlowCheetah et FastKoala de la galerie VisualStudio semblent être de très bons outils qui aident à résoudre ce problème.

Cependant, si vous souhaitez éviter les compléments ou utiliser les principes qu'ils implémentent plus largement tout au long de vos processus de construction / intégration, l'ajout de cela à vos fichiers msbuild * proj est une solution abrégée.

Remarque: il s'agit plus ou moins d'une refonte de la réponse n ° 2 de @ oleksii.

Cela fonctionne pour les projets .exe et .dll:

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

Cela fonctionne pour les projets Web:

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

Notez que cette étape se produit avant même que la construction proprement dite ne commence. La transformation du fichier de configuration se produit dans le dossier du projet. Pour que le web.config transformé soit disponible lors du débogage (un inconvénient de SlowCheetah).

N'oubliez pas que si vous créez le dossier App_Config (ou ce que vous choisissez de l'appeler), les différents fichiers de configuration intermédiaires doivent avoir une Action de construction = Aucune et Copier dans le répertoire de sortie = Ne pas copier.

Cela combine les deux options en un seul bloc. Celui qui convient est exécuté en fonction des conditions. La tâche TransformXml est définie en premier cependant:

<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
la source
Je viens d'essayer cela dans Visual Studio 2017 et cela ne fonctionne pas. Tirer. J'espérais vraiment que cela fonctionnerait, car il semble être le plus simple à mettre en œuvre.
Greg Burghardt
La tâche TransformXml n'est pas définie dans les exemples. J'ajoute une entrée. Vous pouvez le définir dans un fichier mycustom.targets qui sera inclus dans tous vos projets de lancement de votre solution.
Eniola
@GregBurghardt, voulez-vous l'essayer maintenant?
Eniola
Je pourrais essayer. J'ai installé le plugin Config Transform pour Visual Studio, et cela a très bien fonctionné. Je me demande en fait si le plugin fait essentiellement ce que fait votre réponse.
Greg Burghardt
Ok, dis-moi comment ça se passe.
Eniola
1

Voyez si le moteur de transformation XDT (web.config) peut vous aider. Actuellement, il n'est pris en charge nativement que pour les projets Web, mais techniquement, rien ne vous empêche de l'utiliser dans d'autres types d'applications. Il existe de nombreux guides sur l'utilisation de XDT en éditant manuellement les fichiers du projet, mais j'ai trouvé un plugin qui fonctionne très bien: https://visualstudiogallery.msdn.microsoft.com/579d3a78-3bdd-497c-bc21-aa6e6abbc859

Le plugin ne fait qu'aider à configurer la configuration, il n'est pas nécessaire de construire et la solution peut être construite sur d'autres machines ou sur un serveur de build sans que le plugin ou tout autre outil ne soit requis.

TGasdf
la source
Cela devrait être la réponse maintenant. Je viens de l'essayer sur VS 2017 et cela fonctionne comme un charme. Vous n'avez pas besoin de publier le projet. Construisez-le simplement. Fonctionne très bien pour notre projet de test à utiliser dans notre build d'intégration continue afin que nous puissions exécuter des tests Selenium en mode sans tête, mais ils s'exécutent localement avec l'ouverture du navigateur. +1 000 000 si je pouvais.
Greg Burghardt
1

J'ai résolu ce sujet avec la solution que j'ai trouvée ici: http://www.blackwasp.co.uk/SwitchConfig.aspx

En bref, ce qu'ils déclarent: "en ajoutant un événement post-build. [...] Nous devons ajouter ce qui suit:

if "Debug"=="$(ConfigurationName)" goto :nocopy
del "$(TargetPath).config"
copy "$(ProjectDir)\Release.config" "$(TargetPath).config"
:nocopy
Janbro
la source
De loin la méthode la plus simple pour faire ce qui aurait dû être une fonction très simple et essentielle qui a été foirée par des sur-penseurs! Merci Janbro.
BoiseBaked
1

J'ai entendu de bonnes choses à propos de SlowCheetah, mais je n'ai pas pu le faire fonctionner. J'ai fait ce qui suit: ajouter une balise am à chacun pour une configuration spécifique.

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>
Mike
la source
Cela semble être un autre moyen très simple de modifier les fichiers app.config selon la configuration de construction. Mike, avez-vous testé avec les configurations de débogage et de publication standard?
BoiseBaked
0

Après quelques recherches sur la gestion des configurations pour le développement et les builds, etc., j'ai décidé de lancer le mien, je l'ai rendu disponible sur bitbucket à: https://bitbucket.org/brightertools/contemplate/wiki/Home

Ces fichiers de configuration multiples pour plusieurs environnements, c'est un outil de remplacement d'entrée de configuration de base qui fonctionnera avec n'importe quel format de fichier basé sur du texte.

J'espère que cela t'aides.

Mark Redman
la source