2009-03-30 16 views
14

Estoy escribiendo un desarrollo de juegos IDE que crea y compila proyectos .NET (en los que he estado trabajando durante los últimos años) y estoy en proceso de actualizarlo para generar resultados no solo para Windows/Visual Studio, pero también para Linux/MonoDevelop (un proceso tremendamente simple para .NET, pero que aún requiere algunos ajustes).¿Quién copia app.config a app.exe.config?

Como parte de esto, he encontrado que es necesario comenzar a generar un archivo app.config como parte de esto para asignar nombres de DLL dependientes a nombres de dependencia de Linux con elementos <dllmap>. Estoy confundido sobre quién es responsable de copiar el archivo app.config al nombre de salida app.exe.config. En un proyecto de Visual Studio, la acción de compilación para app.config normalmente se configura como "Ninguna" y su configuración indica que no se copiará en ningún lugar, sin embargo, cuando Visual Studio compila el proyecto, genera app.exe.config (aunque a veces he encontrado que esto no es confiable). Cuando uso MSBuild para compilar un archivo de solución generado por el IDE (para fines de depuración), MSBuild copia app.config a app.exe.config. Pero cuando compilo el proyecto con CSharpCodeProvider.CompileAssemblyFromFile, (naturalmente) no le gusta que el archivo de configuración se incluya como código fuente ("app.config (1,1): error CS0116: un espacio de nombres no contiene directamente miembros como campos o métodos "), y por supuesto no lo copia a la salida cuando no lo incluyo como entrada. ¿Es mi responsabilidad simplemente copiar app.config a app.exe.config de forma independiente o existe una forma más estándar de hacerlo?

¿Está cableado para tomar el primer archivo * .config? En mi IDE es concebible que el archivo app.config se renombre o se agregue otro (al igual que en Visual Studio). Me parece extraño que el IDE tenga esta acción secreta para los archivos de configuración (creo que MonoDevelop se comporta de manera similar a este respecto porque tampoco pude encontrar una acción especial para los archivos de configuración). No sé cómo se selecciona qué archivos aplica esta acción secreta.

+0

Para aclarar, mi pregunta es, ya que estoy usando CSharpCodeProvider para compilar el código (sin recurrir a un comando shell como MSBuild para compilar el proyecto), ¿cuál es la forma correcta para obtener el app.exe .config en la salida? – BlueMonkMN

+0

Sugiero usar MSBuild en tu IDE y crear tareas de MSBuild para cualquier salida de compilación especial que generes, para lo cual MSBuild no tiene soporte. Esto permitiría a MSBuild compilar sus soluciones. Además, esto facilitaría la integración de su producto con una integración continua como TeamCity. – grover

+0

MSBuild ya puede compilar mis soluciones. Y cuando lo hace, ya está manejando app.config correctamente. CSharpCodeProvider parece una solución más directa con menos gastos generales que desembolsar a MSBuild. El IDE genera un archivo de solución, pero no lo usa cuando compila internamente. – BlueMonkMN

Respuesta

8

El compilador C# no se preocupa por el archivo de configuración en absoluto. Los entornos de compilación (MSBuild y VS) se encargarán de copiar ese archivo ellos mismos.

+0

Mi IDE no está utilizando MSBuild para compilar el proyecto. Está utilizando CSharpCodeProvider. Entonces, ¿qué debería hacer mi IDE? – BlueMonkMN

+0

Debe copiar el archivo de configuración usando 'File.Copy' después de la compilación. –

+0

Copie el primer archivo * .config a outputname.exe.config e ignore cualquier otro posible archivo * .config (que no debería existir)? – BlueMonkMN

1

Creo que MSBuild es responsable de copiar. Si buscara archivos stock de destino, probablemente encuentre las directivas correspondientes. VS por sí mismo no copia.

1

Tenga en cuenta también que Visual Studio valida el archivo de configuración.

7

Orden:

  1. primer archivo app.config con la acción Ninguno de construcción, en el directorio del proyecto
  2. primer archivo app.config con la acción de crear el contenido, en el directorio del proyecto
  3. primera app.config presentar ante la acción Ninguno de construcción, en un subdirectorio
  4. primer archivo app.config con la acción de crear el contenido, en un subdirectorio

msbuild/xbuild también le permiten anular esto configurando la propiedad $ (AppConfig).

+0

Su mención de la propiedad '$ (AppConfig)' fue realmente útil para mí. Sin embargo, creo que podría mejorar esta respuesta con más antecedentes sobre dónde encontró esta información. Encontré algunas explicaciones adicionales [aquí] (https://timvw.be/2008/03/17/easily-switching-between-appconfig-files-with-msbuild/) pero si hay un enlace oficial que sería aún mejor . Si no, solo una mención del archivo 'targets' sería bienvenida también. – julealgon

0

Una respuesta un poco más técnica - el proyecto hace referencia a Microsoft.CSharp.targets a través de esta clave en el archivo csproj:

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

Este archivo se resolvería a algo así como c:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets, según la versión de marco.

Dentro de ella se han esta sección que hace el trabajo:

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

El archivo app.config parece pasar como una variable de entorno (que se espera que estén presentes, sino que establece que, no me sé):

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

Editar: Por qué se selecciona app.config, ver esta respuesta - https://stackoverflow.com/a/40293508/492336.

El manejo de app.config es especial, es tratado por nombre, el proceso de construcción seleccionará el archivo app.config siguiendo este orden:

  • elegir el valor $ (AppConfig) situado en el proyecto principal.
  • Elija @ (Ninguno) App.Config en la misma carpeta que el proyecto.
  • Elija @ (Contenido) App.Config en la misma carpeta que el proyecto.
  • Elija @ (Ninguna) App.Config en cualquier subcarpeta del proyecto.
  • Elija @ (Contenido) App.Config en cualquier subcarpeta del proyecto.