2009-03-30 6 views
14

J'écris un IDE de développement de jeu qui crée et compile des projets .NET (sur lesquels je travaille depuis quelques années) et je suis en train de le mettre à jour pour générer des sorties non seulement pour Windows/Visual Studio, mais aussi pour Linux/MonoDevelop (un processus très simple pour .NET, mais qui nécessite encore quelques modifications). Dans le cadre de cela, j'ai trouvé nécessaire de commencer à générer un fichier app.config dans le cadre de ce mapper des noms DLL dépendants aux noms de dépendances Linux avec <dllmap> éléments. Je suis confus au sujet de qui est responsable de la copie du fichier app.config au nom de sortie app.exe.config. Dans un projet Visual Studio, l'action de construction pour app.config semble normalement être définie sur "Aucun" et ses paramètres indiquent qu'il ne sera copié nulle part, mais lorsque Visual Studio compile le projet, il génère app.exe.config (bien que j'ai parfois trouvé que ce n'était pas fiable). Lorsque j'utilise MSBuild pour générer un fichier de solution généré par l'EDI (à des fins de débogage), MSBuild copie app.config vers app.exe.config. Mais quand je compile le projet avec CSharpCodeProvider.CompileAssemblyFromFile il (naturellement) n'aime pas le fichier de configuration étant inclus comme code source ("app.config (1,1): erreur CS0116: Un espace de noms ne contient pas directement des membres tels que des champs ou méthodes "), et bien sûr il ne le copie pas en sortie quand je ne l'inclue pas en entrée. Est-ce ma responsabilité de simplement copier app.config à app.exe.config indépendamment, ou y a-t-il une manière plus standard de faire ceci?Qui copie app.config à app.exe.config?

Est-il difficile de prendre le premier fichier * .config? Dans mon IDE, il est concevable que le fichier app.config soit renommé ou qu'un autre soit ajouté (comme dans Visual Studio). Il me semble étrange que l'IDE ait cette action secrète pour les fichiers de configuration (je pense que MonoDevelop se comporte de la même manière à cet égard car je ne trouve pas non plus d'action spéciale pour les fichiers de configuration). Je ne sais pas comment il choisit même à quels fichiers cette action secrète s'applique.

+0

Pour clarifier les choses, ma question est, depuis que je suis en utilisant CSharpCodeProvider pour compiler le code (sans avoir recours à une commande shell, comme MSBuild pour compiler le projet), quelle est la bonne façon d'obtenir le app.exe .config dans la sortie? – BlueMonkMN

+0

Je suggère d'utiliser MSBuild dans votre IDE et de créer des tâches MSBuild pour toute sortie de génération spéciale que vous générez, MSBuild ne prend pas en charge. Cela permettrait MSBuild de compiler à vos solutions. De plus, cela faciliterait l'intégration de votre produit à une intégration continue telle que TeamCity. – grover

+0

MSBuild peut déjà compiler mes solutions. Et quand c'est le cas, il gère déjà app.config correctement. CSharpCodeProvider semble être une solution plus directe avec moins de frais généraux que le décompte vers MSBuild. L'EDI génère un fichier de solution, mais ne l'utilise pas lors de la compilation interne. – BlueMonkMN

Répondre

8

Le compilateur C# ne se soucie pas du tout du fichier de configuration. Les environnements de construction (MSBuild et VS) prendront soin de copier eux-mêmes ce fichier.

+0

Mon IDE n'utilise pas MSBuild pour compiler le projet. Il utilise CSharpCodeProvider. Alors, que devrait faire mon IDE? – BlueMonkMN

+0

Il devrait copier le fichier de configuration en utilisant 'File.Copy' après la compilation. –

+0

Copiez le premier fichier * .config à outputname.exe.config et ignorez tout autre fichier * .config possible (qui ne devrait pas exister)? – BlueMonkMN

1

Je pense que MSBuild est responsable de la copie. Si vous voulez creuser des fichiers stock .target, vous trouverez probablement les directives correspondantes. VS par lui-même ne copie pas.

1

Notez également que Visual Studio valide le fichier de configuration.

7

Ordre:

  1. premier fichier app.config avec l'action Aucune construction, dans le répertoire du projet
  2. premier fichier app.config avec l'action Contenu de construction, dans le répertoire du projet
  3. premier app.config déposer une action Aucune construction, dans un sous-répertoire
  4. premier fichier app.config avec l'action contenu de construction, dans un sous-répertoire

msbuild/xbuild vous permet également de surcharger en définissant la propriété $ (AppConfig).

+0

Votre mention de la propriété '$ (AppConfig)' m'a vraiment été utile. Je pense que vous pourriez améliorer cette réponse avec un peu plus d'informations sur l'endroit où vous avez trouvé cette information. J'ai trouvé quelques explications supplémentaires [ici] (https://timvw.be/2008/03/17/easily-switching-between-appconfig-files-with-msbuild/) mais s'il y a un lien officiel qui serait encore mieux . Sinon, une simple mention du fichier 'targets' serait également la bienvenue. – julealgon

0

Une réponse un peu plus technique - votre projet fait référence Microsoft.CSharp.targets via cette clé dans le fichier csproj:

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

Ce fichier résoudrait à quelque chose comme c:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets, selon votre version du framework.

A l'intérieur de celui-ci vous avez cette section qui fait le travail:

<!-- 
    ============================================================ 
             _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> 

Le fichier App.Config semble être passé comme une variable d'environnement (il est prévu d'être présent, mais qui définit, je don sais pas):

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

Edit: Pour savoir comment app.config est sélectionné, voir cette réponse - https://stackoverflow.com/a/40293508/492336.

Le traitement des app.config est spéciale, elle est traitée par nom, le processus de construction sélectionnera le fichier app.config suivant cet ordre:

  • Choisissez la valeur $ (AppConfig) situé dans le projet principal.
  • Choisissez @ (Aucune) App.Config dans le même dossier que le projet.
  • Choisissez @ (Content) App.Config dans le même dossier que le projet.
  • Choisissez @ (Aucun) App.Config dans n'importe quel sous-dossier du projet.
  • Choisissez @ (Contenu) App.Config dans n'importe quel sous-dossier du projet.