Visual studio no copia archivos de contenido del proyecto indirectamente referenciado


Tengo la siguiente estructura de proyecto:

Library1 <--[project reference]-- Library2 <--[ref]-- Executable
--------                          --------            ----------
ContentFile                      .cs files           .cs files
.cs files

Todas las referencias de proyectos tienen CopyLocal = true.

Cuando compilo el proyecto, el ContentFile se copia al directorio de salida de Library2, pero no al directorio de salida de Executable, lo que significa que falta el ejecutable ContentFile cuando se ejecuta la aplicación.

¿Por qué se copia el archivo de contenido al directorio de salida de Library2, pero no al de Executable? ¿Hay alguna manera de copiarlo también a este último (me gustaría hacerlo sin crear eventos porque estoy seguro de que la gente olvidará eso)?

Estoy buscando una solución razonable y mantenible; una que requiera un esfuerzo mínimo al agregar nuevos proyectos o nuevos archivos de contenido con referencia indirecta, de modo que sea lo más improbable posible simplemente olvidarse de hacerlo.

Usando eventos Post-Build (como xcopy ../Library/bin/Debug/SomeDll.dll bin/Debug); y configurando manualmente el directorio de salida de los proyectos a $(SolutionDir)/bin/... en lugar del predeterminado (por proyecto), ambos se han convertido rápidamente en un enorme desorden. Agregar los archivos de contenido como enlaces en el "proyecto principal" también era demasiado tedioso. Estaría bien si C# tuviera la misma configuración predeterminada para el archivo de salida que Visual C++ (es decir, $SolutionDir/$Platform/$Configuration), pero no lo tiene.

También he considerado no usar el procedimiento estándar de MSBuild y escribir un objetivo de compilación personalizado (como usar gcc en Atmel Studio), pero no llegué muy lejos. Además, quiero que los comandos estándar de Visual Studio "Build" y "Debug" funcionen como normalmente hacer.


ACTUALIZACIÓN:

Aquí hay más detalles sobre lo que estoy haciendo.

Tengo una solución con un proyecto Executable. Además, hay un montón de proyectos que puedes llamar Plugin s. Executable referencias a todos esos Plugin s a través de una referencia de proyecto gestionado.

Dado que los proyectos del plugin se adaptan al ejecutable, pero pueden tener componentes reutilizables, la funcionalidad principal a menudo se implementa en un proyecto External, dejando el proyecto Plugin como un mero envoltorio (no siempre sin embargo).

Dijo External los proyectos a veces usan DLL nativos proporcionados por terceros. Esas DLL se agregan al proyecto External como un archivo de contenido y tienen Copy to output dir establecido en Copy always. Así que la estructura se parece al diagrama de arriba:

External <---------------[is not aware of]--------------------+
--------                                                      |
.cs files <--[reference]-- PluginWrapper <--[reference]-- Executable
"Native DLL"               -------------                  ----------
                           .cs files                      .cs files

Lo extraño es que el" DLL nativo " se copia al directorio de salida de External (obviamente), así como PluginWrapper's, pero no Executable's.

El flujo de trabajo del desarrollador sería entonces escribir un External eso funciona como una entidad completamente aislada ( están siendo reutilizados muy a menudo), envolverlo con un PluginWrapper, y luego solo añadir una referencia de proyecto a la PluginWrapper a Executable. Me parece extraño que esto es aparentemente una cosa tan poco común de hacer.

Pensé que quizás editar el XML de destino de MSBuild de Executable (para incluir también archivos de contenido indirectamente referenciados) podría haber resuelto el problema.

Es posible que desee buscar en la adición de las DLL a los proyectos como recursos incrustados como sugerido, pero incrustar DLL nativos como ese me parece raro. Al final, cambiar el flujo de trabajo del desarrollador eliminando el '[is not aware of]' del diagrama anterior y agregando una referencia de proyecto a External, como sugirió Brenda Bell, podría ser la solución más sensata, incluso si no es ideal.

Actualización 2

Tenga en cuenta que la idea de recurso incrustado puede no funcionar en todos los casos. Si es necesario colocar una dependencia en el directorio del ejecutable (no cwd o cualquier cosa), entonces esto puede no funcionar debido a la falta de privilegios de administrador en la carpeta de instalación (para descomprimir el archivo del recurso incrustado). Suena raro, pero este fue un problema serio con una de las bibliotecas de terceros que estábamos utilizando.

Author: dialer, 2012-09-12

4 answers

Añada la referencia Library1 al proyecto ejecutable.

 18
Author: Brenda Bell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-05 01:22:04

EDITAR:

Puede poner todo el contenido en un proyecto separado, establecer todas sus entradas en "contenido" y "copiar siempre" y hacer referencia a ese proyecto desde un archivo Externo y Ejecutable

-

IMO está buscando recursos incrustados, no archivos de contenido.

Cuando compila la Biblioteca 1, los archivos de contenido se colocan en su carpeta bin. Cuando se compila la Biblioteca 2, el compilador reconoce el código referenciado y lo incluye (Biblioteca 1.dll) pero los archivos de contenido no se reconocen desde no se mencionan en ninguna parte de la Biblioteca 2. Lo mismo ocurre cuando se enlaza la Biblioteca 2 con el ejecutable.

Si sus archivos de contenido son relativamente pequeños (iconos, plantillas, etc.) y no prevé la necesidad de editarlos si pierde el código fuente, puede incrustarlos como recursos y proporcionar un método público para devolver el contenido, como:

 public static Stream GetResourceContent(string rName){
     string resName = System.Reflection.Assembly
         .GetExecutingAssembly().GetManifestResourceNames()
         .FirstOrDefault(rn => rn.EndsWith("."+rName));
    if(resName!=null)
        return System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(resName);
    else
        return null;
}

Si su contenido está obligado a cambiar, como plantillas, etc., considere incluir una copia con el proyecto ejecutable

 5
Author: Sten Petrov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-10 15:46:30

Otra opción sería incrustar ContentFile como un recurso dentro del ensamblado de Library1 y extraerlo usando Assembly.GetManifestResource().

Vea estos enlaces para más información:

Http://www.attilan.com/2006/08/accessing-embedded-resources-using.html

Http://blogs.msdn.com/b/alexdan/archive/2007/12/19/loading-embedded-resources-in-c-using-getmanifestresourcestream.aspx

 3
Author: MvdD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-05 03:47:32

Una variación de la respuesta de Brenda sería agregar el archivo(s) de contenido de Library1 como Enlace(s) en el proyecto Ejecutable. Aún tendría las entradas en el proyecto, pero no necesitaría administrar varias copias de cada archivo.

 0
Author: Chris Peach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-14 01:23:52