Come selezionare app.config differenti per diverse configurazioni di build


115

Ho un progetto di tipo dll che contiene test di integrazione MSTest. Sulla mia macchina i test vengono superati e voglio che lo stesso accada su un server CI (io uso TeamCity). Ma i test falliscono, perché ho bisogno di modificare alcune impostazioni in app.config. Questo è il motivo per cui stavo pensando di avere un secondo file app.config separato che conterrà le impostazioni per il server CI.

Quindi mi piacerebbe avere

/ Sln
 / Proj
  app.config (penso che questo sia richiesto da VS)
  app.Release.config (questo è un file di configurazione indipendente autonomo)

Pertanto, se seleziono Release configuration in build config su CI, vorrei utilizzare il file app.Release.config invece di app.config

Problema
Questo non sembra essere semplice per progetti di tipo .dll semplici. Per i progetti web, posso eseguire trasformazioni di configurazione web. Ho trovato un trucco su come eseguire queste trasformazioni per un progetto di tipo dll, ma non sono un grande fan degli hack.

Domanda
Qual è un approccio standard per modificare i file app.config a seconda della configurazione della build per i progetti .NET (come Debug, Release, ...)?

Risposte:


154

Usa il plugin SlowCheetah . Per ulteriori opzioni e dettagli su come utilizzare SlowCheetah, continua a leggere.

Come hai già notato, non esiste un modo semplice e predefinito per utilizzare diversi file di configurazione per un progetto di tipo Libreria (.dll) . Il motivo è che il pensiero corrente è: "Non è necessario"! Gli sviluppatori di framework ritengono che sia necessaria la configurazione per il file eseguibile: che si tratti di una console, desktop, web, app mobile o qualcos'altro. Se inizi a fornire la configurazione per una dll , potresti finire con qualcosa che posso chiamare un inferno di configurazione . Potresti non capire più (facilmente) perché questa e quella variabili hanno valori così strani che apparentemente provengono dal nulla.

"Aspetta", - potresti dire, "ma ne ho bisogno per la mia integrazione / unit test, ed è una libreria!". E questo è vero e questo è quello che puoi fare (scegli solo uno, non mescolare):

1. SlowCheetah - trasforma il file di configurazione corrente

Puoi installare SlowCheetah , un plug-in di Visual Studio che esegue tutti i poking (o trasformazioni) XML di basso livello per te. Il modo in cui funziona, brevemente:

  • Installa SlowCheetah e riavvia Visual Studio (Visual Studio> Strumenti> Estensioni e aggiornamenti ...> Online> Raccolta di Visual Studio> cerca "Slow Cheetah")
  • Definisci le configurazioni della tua soluzione ( Debug e Release sono presenti per impostazione predefinita), puoi aggiungerne altri (fai clic con il tasto destro sulla soluzione in Esplora soluzioni > Gestione configurazione ... > Configurazione soluzione attiva > Nuovo ...
  • Aggiungi un file di configurazione se necessario
  • Fare clic con il tasto destro sul file di configurazione> Aggiungi trasformazione
    • Questo creerà i file di trasformazione, uno per la tua configurazione
    • I file di trasformazione funzionano come iniettori / mutatori, trovano il codice XML necessario nel file di configurazione originale e inseriscono nuove righe o mutano il valore necessario, qualunque cosa tu gli dica di fare

2. Giocherellare con il file .proj - copia e rinomina un nuovo file di configurazione

Originariamente ripreso da qui . È un'attività MSBuild personalizzata che puoi incorporare nel file .proj di Visual Studio . Copia e incolla il codice seguente nel file di progetto

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

Ora crea una cartella nel progetto chiamato Confige aggiungi nuovi file lì: App.Debug.config , App.Release.config e così via. Ora, a seconda della configurazione, Visual Studio selezionerà il file di configurazione da una Configcartella e lo copia e rinominerà nella directory di output. Quindi, se hai selezionato il progetto PatternPA.Test.Integration e una configurazione di debug , nella cartella di output dopo la compilazione troverai un file PatternPA.Test.Integration.dll.config che è stato copiato Config\App.Debug.confige rinominato in seguito.

Queste sono alcune note che puoi lasciare nei file di configurazione

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

In Visual Studio puoi avere qualcosa di simile

Struttura del progetto

3. Utilizzare file di scripting all'esterno di Visual Studio

Ogni strumento di compilazione (come NAnt , MSBuild ) fornirà funzionalità per trasformare il file di configurazione a seconda della configurazione. Ciò è utile se si crea la soluzione su una macchina di compilazione, dove è necessario avere un maggiore controllo su cosa e come si prepara il prodotto per il rilascio.

Ad esempio, puoi utilizzare l'attività di pubblicazione su Web dll per trasformare qualsiasi file di configurazione

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

La tua seconda soluzione funziona bene, ma non per la pubblicazione di progetti web. Dopo aver pubblicato un progetto ASP.NET, viene pubblicato il web.config originale.
Massood Khaari

3
@MassoodKhaari devi assicurarti che questa attività venga chiamata per la destinazione di pubblicazione. Quando pubblichi un progetto, viene chiamato un target di build separato, che potrebbe non essere chiamato come AfterBuildtarget predefinito . Durante la compilazione tipica, il AfterBuildtarget viene chiamato per impostazione predefinita. Dovrebbe esserci una soluzione rapida per il caso di pubblicazione
oleksii

1
Hai usato il tuo secondo metodo (più o meno). Sono andato alle proprietà del progetto e ho modificato BeforeBuild per copiare l' App.<Target>.configover App.confignella directory del progetto , non nella directory di output.
SparK

@oleksii Hai ragione. Ma non sono ancora riuscito a trovare la destinazione utilizzata dal mio processo di pubblicazione sul Web (in Visual Studio 2013).
Massood Khaari

1
Sto usando il secondo metodo, ma avevo bisogno di aggiungere una condizione alla destinazione AfterBuild per assicurarmi che il file esista effettivamente prima di eliminarlo. Ho una configurazione di build di debug, che fondamentalmente utilizza solo il file App.config predefinito, ma non avevo App.Debug.config, il che significava che il passaggio di build non avrebbe avuto esito positivo. Ho appena aggiunto Condition="Exists('$(ProjectDir)App.$(Configuration).config')".
Siewers

23

Puoi provare il seguente approccio:

  1. Fare clic con il pulsante destro del mouse sul progetto in Esplora soluzioni e selezionare Scarica progetto .
  2. Il progetto verrà scaricato. Fare nuovamente clic con il tasto destro del mouse sul progetto e selezionare Modifica <YourProjectName> .csproj .
  3. Ora puoi modificare il file di progetto all'interno di Visual Studio.
  4. Individuare la posizione nel file * .csproj in cui è incluso il file di configurazione dell'applicazione. Apparirà come:
    <ItemGroup>
        <None Include = "App.config" />
    </ ItemGroup>
  1. Sostituisci queste righe con le seguenti:
    <ItemGroup Condition = "'$ (Configuration)' == 'Debug'">
        <None Include = "App.Debug.config" />
    </ ItemGroup>

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

Non ho provato questo approccio ai app.configfile, ma ha funzionato bene con altri elementi dei progetti di Visual Studio. Puoi personalizzare il processo di costruzione in quasi tutti i modi che preferisci. Comunque fammi sapere il risultato.


Tnx per la risposta, ma questo non funziona con app.config. VS richiede un obbligatorio app.confige non applica la configurazione di rilascio se uso VS build o Teamcity VS sln build runner.
oleksii


1
Perché questa risposta ha così tanti voti positivi? L'ho provato e non funziona. Infatti sia in modalità debug che in modalità di rilascio non è presente il file App.config e quindi, non è presente alcun file corrispondente nella cartella di output. I file App.Debug.config e App.Release.config non hanno alcun significato per Visual Studio.
MarkusParker

Non funziona: .csproj non può essere aperto, messaggio di errore "gli elementi al di fuori degli elementi Target devono avere: Includi, Aggiorna o Rimuovi"
Elo

12

Dovresti considerare ConfigGen . È stato sviluppato per questo scopo. Produce un file di configurazione per ogni macchina di distribuzione, basato su un file modello e un file di impostazioni. So che questo non risponde in modo specifico alla tua domanda, ma potrebbe benissimo rispondere al tuo problema.

Quindi, invece di Debug, Rilascio ecc., Potresti avere Test, UAT, Produzione ecc. Puoi anche avere impostazioni diverse per ogni macchina dello sviluppatore, in modo da poter generare una configurazione specifica per la tua macchina di sviluppo e modificarla senza influire sulla distribuzione di qualcun altro .

Un esempio di utilizzo potrebbe essere ...

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

Se lo inserisci nel tuo file .csproj e hai i seguenti file ...

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

... allora questo sarà il risultato ...

Dal primo comando, un file di configurazione generato per ogni ambiente specificato nel file xls, posto nella directory di output $ (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>

Dal secondo comando, l'App.config locale utilizzato sulla macchina di sviluppo verrà sostituito con la configurazione generata specificata dallo switch locale (-l) e dallo switch filename (-n).


2
Tnx per la risposta, questo non sembra male. Ma ci sono alcuni svantaggi, mostra solo 75 download (quindi non è maturo) e funziona solo con .xls o .xlsx. Non voglio davvero dipendere da un altro formato di documento personalizzato per operazioni semplici. Stavo cercando un approccio più standard ...
oleksii

2
Giusto punto, anche se dice 194 download su CodePlex, xls è un foglio di calcolo, difficilmente un formato personalizzato, e conosco tre principali banche di investimento che ne hanno approvato l'uso, quindi se è abbastanza buono per loro ... Inoltre, uno delle funzionalità attualmente richieste è utilizzare xml per le impostazioni. È quasi pronto, ma preferisco comunque l'approccio del foglio di calcolo. È molto più facile vedere ogni impostazione per ogni ambiente in una visualizzazione tabulare
Daniel Dyson

Siamo ora nelle fasi finali del test di una versione di configGen che può essere utilizzata per generare file di testo semplice, non solo xml. Quindi, se vuoi generare css, sql, javascript specifici per l'ambiente, tieni d'occhio il sito configGen
Daniel Dyson

grazie Daniel per la soluzione, questo è esattamente quello che stavo cercando. Lo proverò.
Bhupinder Singh

10

Usando lo stesso approccio di Romeo, l'ho adattato a Visual Studio 2010:

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

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

Qui è necessario mantenere entrambi i file App.config in directory diverse (appDebug e appRelease). L'ho provato e funziona bene!


3

Sto usando lo strumento XmlPreprocess per la manipolazione dei file di configurazione. Utilizza un file di mappatura per più ambienti (o più destinazioni di build nel tuo caso). È possibile modificare il file di mappatura da Excel. È molto facile da usare.


3

SlowCheetah e FastKoala della Galleria di VisualStudio sembrano essere ottimi strumenti che aiutano a risolvere questo problema.

Tuttavia, se si desidera evitare componenti aggiuntivi o utilizzare i principi che implementano in modo più esteso durante i processi di compilazione / integrazione, aggiungerlo ai file msbuild * proj è una soluzione abbreviata.

Nota: questa è più o meno una rielaborazione del numero 2 della risposta di @ oleksii.

Funziona per i progetti .exe e .dll:

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

Funziona per progetti web:

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

Nota che questo passaggio avviene anche prima che inizi la build vera e propria. La trasformazione del file di configurazione avviene nella cartella del progetto. In modo che il web.config trasformato sia disponibile durante il debug (uno svantaggio di SlowCheetah).

Ricorda che se crei la cartella App_Config (o qualsiasi altra cosa tu scelga di chiamarla), i vari file di configurazione intermedi dovrebbero avere un'azione Build = Nessuno e Copia nella directory di output = Non copiare.

Questo combina entrambe le opzioni in un blocco. Quello appropriato viene eseguito in base alle condizioni. Tuttavia, l'attività TransformXml viene definita prima:

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


L'ho appena provato in Visual Studio 2017 e non funziona. Sparare. Speravo davvero che funzionasse, perché sembra il più facile da implementare.
Greg Burghardt

L'attività TransformXml non è definita negli esempi. Sto aggiungendo una voce. Puoi definirlo in un file mycustom.targets che viene incluso in tutti i tuoi progetti di lancio nella tua soluzione.
Eniola

@ GregBurghardt, vuoi provarlo ora?
Eniola

Potrei fare un tentativo. Ho installato il plug-in Config Transform per Visual Studio e ha funzionato molto bene. In realtà mi chiedo se il plugin fondamentalmente fa quello che fa la tua risposta.
Greg Burghardt

Ok, fammi sapere come va.
Eniola

1

Verifica se il motore di trasformazione XDT (web.config) può aiutarti. Attualmente è supportato nativamente solo per i progetti web, ma tecnicamente non c'è nulla che ti impedisca di usarlo in altri tipi di applicazioni. Esistono molte guide su come utilizzare XDT modificando manualmente i file di progetto, ma ho trovato un plugin che funziona alla grande: https://visualstudiogallery.msdn.microsoft.com/579d3a78-3bdd-497c-bc21-aa6e6abbc859

Il plug-in aiuta solo a impostare la configurazione, non è necessario compilare e la soluzione può essere costruita su altre macchine o su un server di compilazione senza che sia necessario il plug-in o altri strumenti.


Questa dovrebbe essere la risposta ora. L'ho appena provato su VS 2017 e funziona a meraviglia. Non è necessario pubblicare il progetto. Basta costruirlo. Funziona alla grande per il nostro progetto di test da utilizzare nella nostra build di integrazione continua in modo da poter eseguire test Selenium in modalità headless, ma localmente vengono eseguiti con il browser che si apre. +1.000.000 se potessi.
Greg Burghardt

1

Ho risolto questo argomento con la soluzione che ho trovato qui: http://www.blackwasp.co.uk/SwitchConfig.aspx

In breve, ciò che affermano è: "aggiungendo un evento post-build. [...] Dobbiamo aggiungere quanto segue:

if "Debug"=="$(ConfigurationName)" goto :nocopy
del "$(TargetPath).config"
copy "$(ProjectDir)\Release.config" "$(TargetPath).config"
:nocopy

Di gran lunga il metodo più semplice per fare quella che avrebbe dovuto essere una funzione molto semplice ed essenziale che è stata rovinata da pensatori eccessivi! Grazie Janbro.
BoiseBaked

1

Ho sentito parlare bene di SlowCheetah, ma non sono riuscito a farlo funzionare. Ho fatto quanto segue: aggiungi un tag am a ciascuno per una configurazione specifica.

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>

Questo sembra un altro modo semplicissimo per modificare i file app.config in base alla configurazione della build. Mike, hai provato con le configurazioni standard di debug e rilascio?
BoiseBaked

0

Dopo alcune ricerche sulla gestione delle configurazioni per lo sviluppo e le build, ecc., Ho deciso di lanciarne uno mio, l'ho reso disponibile su bitbucket a: https://bitbucket.org/brightertools/contemplate/wiki/Home

Questo più file di configurazione per più ambienti, è uno strumento di sostituzione della voce di configurazione di base che funzionerà con qualsiasi formato di file basato su testo.

Spero che questo ti aiuti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.