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.
4 answers
Añada la referencia Library1 al proyecto ejecutable.
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
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
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.
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