2009-03-30 11 views
14

Sto scrivendo un IDE per lo sviluppo di giochi che crea e compila progetti .NET (su cui ho lavorato negli ultimi anni) e sono in fase di aggiornamento per generare output non solo per Windows/Visual Studio, ma anche per Linux/MonoDevelop (un processo incredibilmente semplice per .NET, ma che richiede ancora alcune modifiche).Chi copia app.config in app.exe.config?

Come parte di questo, ho trovato necessario avviare la generazione di un file app.config come parte di questo per mappare i nomi DLL dipendenti ai nomi di dipendenza Linux con elementi <dllmap>. Sono confuso da chi è responsabile della copia del file app.config nel nome di output app.exe.config. In un progetto di Visual Studio, l'azione Build per app.config sembra essere normalmente impostata su "Nessuno" e le sue impostazioni indicano che non verrà copiata da nessuna parte, ma quando Visual Studio compila il progetto genera app.exe.config (anche se a volte ho trovato questo inaffidabile). Quando uso MSBuild per creare un file di soluzione generato dall'IDE (a scopo di debug), MSBuild copia app.config in app.exe.config. Ma quando compilo il progetto con CSharpCodeProvider.CompileAssemblyFromFile (naturalmente) non piace il file di configurazione che viene incluso come codice sorgente ("app.config (1,1): errore CS0116: Uno spazio dei nomi non contiene direttamente membri come i campi o metodi "), e ovviamente non lo copia sull'output quando non lo includo come input. È mia responsabilità copiare semplicemente app.config in app.exe.config in modo indipendente, oppure esiste un modo più standard per farlo?

È cablato il primo file * .config? Nel mio IDE è concepibile che il file app.config venga rinominato o aggiunto a un altro (proprio come in Visual Studio). Mi sembra strano che l'IDE abbia questa azione segreta per i file di configurazione (credo che MonoDevelop si comporti allo stesso modo in questo senso perché non ho trovato nemmeno un'azione speciale per i file di configurazione). Non so come si scelga anche a quali file si applica questa azione segreta.

+0

Per chiarire, la mia domanda è, dal momento che sto usando CSharpCodeProvider per compilare il codice (senza ricorrere a un comando di shell come MSBuild per compilare il progetto), qual è il modo corretto per ottenere l'app.exe .config nell'output? – BlueMonkMN

+0

Suggerisco di usare MSBuild nel tuo IDE e creare attività MSBuild per qualsiasi output di generazione speciale che generi, di cui MSBuild non ha supporto. Ciò consentirebbe a MSBuild di compilare le tue soluzioni. Inoltre, questo renderebbe il tuo prodotto più facile da integrare con un'integrazione continua come TeamCity. – grover

+0

MSBuild può già compilare le mie soluzioni. E quando lo fa, sta già gestendo correttamente app.config. CSharpCodeProvider sembra una soluzione più diretta con un sovraccarico minore rispetto al bombardamento su MSBuild. L'IDE genera un file di soluzione, ma non lo usa durante la compilazione interna. – BlueMonkMN

risposta

8

Il compilatore C# non si preoccupa del file di configurazione. Gli ambienti di compilazione (MSBuild e VS) si occuperanno di copiare il file stesso.

+0

Il mio IDE non utilizza MSBuild per compilare il progetto. Sta usando CSharpCodeProvider. Quindi cosa dovrebbe fare il mio IDE? – BlueMonkMN

+0

Dovrebbe copiare il file di configurazione usando 'File.Copy' dopo la compilazione. –

+0

Copiare il primo file * .config in outputname.exe.config e ignorare qualsiasi altro file * .config possibile (che non dovrebbe esistere)? – BlueMonkMN

1

Penso che MSBuild è responsabile per la copia. Se dovessi scavare attraverso i file .target di azioni, probabilmente troverai le direttive corrispondenti. VS da solo non copia.

1

Si noti inoltre che Visual Studio convalida il file di configurazione.

7

ordine:

  1. primo file app.config con l'azione Nessuno costruire, nella directory del progetto
  2. primo file app.config con l'azione creare contenuti, nella directory del progetto
  3. primo app.config depositare presso azione Nessuno costruire, in una sottodirectory
  4. primo file app.config con l'azione creare contenuti, in una sottodirectory

msbuild/xbuild consente inoltre di sovrascrivere ciò impostando la proprietà $ (AppConfig).

+0

La tua menzione della proprietà '$ (AppConfig)' mi è stata di grande aiuto. Mi sento come se tu potessi migliorare questa risposta con qualche altro background su dove hai trovato questa informazione. Ho trovato alcune spiegazioni extra [qui] (https://timvw.be/2008/03/17/easily-switching-between-appconfig-files-with-msbuild/) ma se c'è un link ufficiale che sarebbe ancora meglio . Altrimenti, solo una menzione del file 'targets' sarebbe ben accetta. – julealgon

0

Una risposta un po 'più tecnico - il progetto fa riferimento a Microsoft.CSharp.targets tramite questa chiave nel file csproj:

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

Questo file risolverebbe a qualcosa come c:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets, a seconda della versione framework.

All'interno di esso si hanno questa sezione, che fa il lavoro:

<!-- 
    ============================================================ 
             _CopyAppConfigFile 

    Copy the application config file. 
    ============================================================ 
    --> 
    <Target 
     Name="_CopyAppConfigFile" 
     Condition=" '@(AppConfigWithTargetPath)' != '' " 
     Inputs="@(AppConfigWithTargetPath)" 
     Outputs="@(AppConfigWithTargetPath->'$(OutDir)%(TargetPath)')"> 

    <!-- 
     Copy the application's .config file, if any. 
     Not using SkipUnchangedFiles="true" because the application may want to change 
     the app.config and not have an incremental build replace it. 
     --> 
    <Copy 
     SourceFiles="@(AppConfigWithTargetPath)" 
     DestinationFiles="@(AppConfigWithTargetPath->'$(OutDir)%(TargetPath)')" 
     OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)" 
     Retries="$(CopyRetryCount)" 
     RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)" 
     UseHardlinksIfPossible="$(CreateHardLinksForAdditionalFilesIfPossible)" 
      > 

     <Output TaskParameter="DestinationFiles" ItemName="FileWrites"/> 

    </Copy> 

    </Target> 

file App.config sembra essere passato come una variabile d'ambiente (ci si aspetta di essere presente, ma che lo imposta, io don 't know):

<ItemGroup> 
    <AppConfigWithTargetPath Include="$(AppConfig)" Condition="'$(AppConfig)'!=''"> 
    <TargetPath>$(TargetFileName).config</TargetPath> 
    </AppConfigWithTargetPath> 
</ItemGroup> 

Edit: Per come è selezionata app.config, vedere questa risposta - https://stackoverflow.com/a/40293508/492336.

Il trattamento dei app.config è speciale, esso viene trattato per nome, il processo di generazione selezionerà il file app.config seguendo questo ordine:

  • scegliere il valore $ (AppConfig) impostato in il progetto principale.
  • Scegliere @ (Nessuno) App.Config nella stessa cartella del progetto.
  • Scegliere @ (Contenuto) App.Config nella stessa cartella del progetto.
  • Scegliere @ (Nessuno) App.Config in qualsiasi sottocartella nel progetto.
  • Scegliere @ (Contenuto) App.Config in qualsiasi sottocartella nel progetto.