MSBuild no copia referencias (archivos DLL) si usa dependencias de proyecto en solución

Tengo cuatro proyectos en mi solución de Visual Studio (todos orientados a .NET 3.5). Para mi problema, solo estos dos son importantes:

  1. MyBaseProject <- esta biblioteca de clase hace referencia a un archivo DLL de terceros (elmah.dll)
  2. MyWebProject1 <- este proyecto de aplicación web tiene una referencia a MyBaseProject

Agregué la referencia elmah.dll a MyBaseProject en Visual Studio 2008 haciendo clic en “Agregar referencia …” → pestaña “Examinar” → seleccionando “elmah.dll”.

Las propiedades de la referencia Elmah son las siguientes:

  • Alias ​​- global
  • Copiar local – verdadero
  • Cultura –
  • Descripción – Módulos y controladores de registro de errores (ELMAH) para ASP.NET
  • Tipo de archivo – Ensamblaje
  • Ruta – D: \ webs \ otherfolder \ _myPath \ __ tools \ elmah \ Elmah.dll
  • Resuelto – Verdadero
  • Versión en tiempo de ejecución – v2.0.50727
  • Versión especificada – falso
  • Nombre fuerte – falso
  • Versión – 1.0.11211.0

En MyWebProject1 agregué la referencia al Proyecto MyBaseProject por: “Agregar referencia …” → pestaña “Proyectos” → seleccionando “MyBaseProject”. Las Propiedades de esta referencia son las mismas excepto los siguientes miembros:

  • Descripción –
  • Ruta de acceso – D: \ webs \ CMS \ MyBaseProject \ bin \ Debug \ MyBaseProject.dll
  • Versión – 1.0.0.0

Si ejecuto la comstackción en Visual Studio, el archivo elmah.dll se copia al directorio bin de MyWebProject1 , junto con MyBaseProject.dll.

Sin embargo, si limpio y ejecuto MSBuild para la solución (a través de D: \ webs \ CMS> C: \ WINDOWS \ Microsoft.NET \ Framework \ v3.5 \ MSBuild.exe / t: ReBuild / p: Configuration = Debug MyProject.sln ) elmah.dll falta en el directorio bin de MyWebProject1, ¡aunque la comstackción en sí no contiene advertencias ni errores!

Ya me aseguré de que el .csproj de MyBaseProject contiene el elemento privado con el valor “true” (que debería ser un alias para ” copiar local ” en Visual Studio):

 False ..\mypath\__tools\elmah\Elmah.dll **true**  

(La etiqueta privada no apareció en el xml de .csproj por defecto, aunque Visual Studio dijo “copiar local” como verdadero. Cambié “copiar local” a falso – guardado – y lo configuré en verdadero otra vez – ¡guardar!)

¿Qué pasa con MSBuild? ¿Cómo obtengo la referencia (elmah.dll) copiada en el contenedor MyWebProject1?

¡NO quiero agregar una acción de copia postconstrucción al comando postbuild de cada proyecto! (¡Imagine que muchos proyectos dependen de MyBaseProject!)

No estoy seguro de por qué es diferente cuando se crea entre Visual Studio y MsBuild, pero esto es lo que encontré cuando encontré este problema en MsBuild y Visual Studio.

Explicación

Para un escenario de muestra, digamos que tenemos el proyecto X, el ensamblado A y el ensamblado B. El ensamblaje A hace referencia al ensamblaje B, por lo que el proyecto X incluye una referencia tanto a A como a B. Además, el proyecto X incluye un código que hace referencia al ensamblaje A (por ejemplo, A. SomeFunction ()). Ahora, crea un nuevo proyecto Y que hace referencia al proyecto X.

Entonces la cadena de dependencia se ve así: Y => X => A => B

Visual Studio / MSBuild intenta ser inteligente y solo trae referencias al proyecto Y que detecta como requerido por el proyecto X; lo hace para evitar la contaminación de referencia en el proyecto Y. El problema es que, dado que el proyecto X en realidad no contiene ningún código que utilice explícitamente el ensamblado B (por ejemplo, B.SomeFunction ()), VS / MSBuild no detecta que se requiere B por X, y por lo tanto no lo copia en el directorio de Y del paquete de Y; solo copia los ensamblajes X y A.

Solución

Tiene dos opciones para resolver este problema, las cuales darán como resultado que el ensamblado B se copie en el directorio de Y del contenedor de Y:

  1. Agregue una referencia al conjunto B en el proyecto Y.
  2. Agregue código ficticio a un archivo en el proyecto X que usa el ensamblado B.

Personalmente prefiero la opción 2 por un par de razones.

  1. Si agrega otro proyecto en el futuro que haga referencia al proyecto X, no deberá recordar incluir también una referencia al ensamblado B (como si tuviera que ver con la opción 1).
  2. Puede tener comentarios explícitos que indiquen por qué el código falso debe estar allí y no para eliminarlo. Entonces, si alguien elimina el código por accidente (por ejemplo, con una herramienta de refactorización que busca el código no utilizado), puede ver fácilmente desde el control de origen que el código es necesario y restaurarlo. Si usa la opción 1 y alguien usa una herramienta de refactorización para limpiar las referencias no utilizadas, no tiene ningún comentario; Simplemente verá que se eliminó una referencia del archivo .csproj.

Aquí hay una muestra del “código ficticio” que normalmente agrego cuando encuentro esta situación.

  // DO NOT DELETE THIS CODE UNLESS WE NO LONGER REQUIRE ASSEMBLY A!!! private void DummyFunctionToMakeSureReferencesGetCopiedProperly_DO_NOT_DELETE_THIS_CODE() { // Assembly A is used by this file, and that assembly depends on assembly B, // but this project does not have any code that explicitly references assembly B. Therefore, when another project references // this project, this project's assembly and the assembly A get copied to the project's bin directory, but not // assembly B. So in order to get the required assembly B copied over, we add some dummy code here (that never // gets called) that references assembly B; this will flag VS/MSBuild to copy the required assembly B over as well. var dummyType = typeof(B.SomeClass); Console.WriteLine(dummyType.FullName); } 

Simplemente lo trato así. Vaya a las propiedades de su referencia y haga esto:

 Set "Copy local = false" Save Set "Copy local = true" Save 

y eso es.

Visual Studio 2010 no pone inicialmente: True en la etiqueta de referencia y establecer “copy local” en false hace que cree la etiqueta. Luego lo establecerá en verdadero y falso en consecuencia.

Si no está utilizando el ensamblado directamente en el código, entonces Visual Studio, al tratar de ser útil, detecta que no se usa y no lo incluye en la salida. No estoy seguro de por qué está viendo un comportamiento diferente entre Visual Studio y MSBuild. Podría intentar establecer el resultado de comstackción en el diagnóstico para ambos y comparar los resultados para ver dónde diverge.

En cuanto a su referencia de elmah.dll, si no está haciendo referencia directamente en el código, podría agregarlo como un elemento a su proyecto y establecer la acción de comstackción en el Content y el directorio copiar en resultados en Always .

Echa un vistazo a:

Este hilo del foro de MSBuild comencé

¡Encontrarás mi solución temporal / solución alternativa allí!

(MyBaseProject necesita un código que haga referencia a algunas clases (lo que sea) desde el elmah.dll para que elmah.dll se copie al contenedor de MyWebProject1).

Yo tuve el mismo problema.

Compruebe si la versión del marco de trabajo de su proyecto es la misma que la versión marco de la dll que puso como referencia.

En mi caso, mi cliente se compiló usando “Framework 4 Client” y el DLL estaba en “Framework 4”.

El problema al que me enfrentaba era que tenía un proyecto que depende de un proyecto de biblioteca. Para construir, estaba siguiendo estos pasos:

 msbuild.exe myproject.vbproj /T:Rebuild msbuild.exe myproject.vbproj /T:Package 

Eso, por supuesto, significaba que estaba perdiendo los archivos dll de mi biblioteca en el contenedor y, lo más importante, en el archivo comprimido del paquete. Encontré que esto funciona perfectamente:

 msbuild.exe myproject.vbproj /T:Rebuild;Package 

No tengo idea de por qué este trabajo o por qué no lo hizo en primer lugar. Pero espero que ayude.

Como Alex Burtsev mencionó en un comentario cualquier cosa que solo se use en un diccionario de recursos XAML, o en mi caso, cualquier cosa que solo se use en XAML y no en el código subyacente, no se considera ‘en uso’ por MSBuild.

Así que simplemente actualizar una referencia ficticia a una clase / componente en el ensamblaje con algún código detrás fue suficiente para convencer a MSBuild de que el ensamblaje estaba realmente en uso.

Cambiar el marco de destino de .NET Framework 4 Client Profile a .NET Framework 4 solucionó este problema para mí.

Entonces en su ejemplo: establezca el marco de destino en MyWebProject1 a .NET Framework 4

Simplemente tuve exactamente el mismo problema y resultó ser el hecho de que 2 proyectos en la misma solución estaban haciendo referencia a una versión diferente de la biblioteca de terceros.

Una vez que corregí todas las referencias, todo funcionó perfectamente.

Tuve el mismo problema y el dll era una referencia cargada dinámicamente. Para resolver el problema he agregado un “uso” con el espacio de nombres de la dll. Ahora el dll se copia en la carpeta de salida.

Esto requiere agregar un archivo .targets a su proyecto y configurarlo para incluirlo en la sección de inclusión del proyecto.

Vea mi respuesta aquí para el procedimiento.

Hacer referencia a los ensamblajes que no se usan durante la comstackción no es la práctica correcta. Debe boost su archivo de comstackción para que copie los archivos adicionales. Ya sea mediante el uso de un evento de comstackción posterior o actualizando el grupo de propiedades.

Algunos ejemplos se pueden encontrar en otras publicaciones

  • MSBuild para copiar archivos generados dinámicamente como parte de la dependencia del proyecto
  • VS2010 Cómo incluir archivos en el proyecto, copiarlos para generar el directorio de salida automáticamente durante la comstackción o publicación

Usando el esquema de deadlydog,

Y => X => A => B ,

mi problema fue que cuando construí Y, los ensamblajes (A y B, los 15 de ellos) de X no aparecían en la carpeta de Y’s bin.

Lo resolví eliminando la referencia X de Y, guardar, comstackr, luego volver a agregar referencia X (una referencia de proyecto), y guardar, comstackr, y A y B comenzaron a aparecer en la carpeta Y’s bin.

Otro escenario donde esto aparece es si está utilizando el tipo de proyecto “Sitio web” anterior en Visual Studio. Para ese tipo de proyecto, no puede hacer referencia a .dlls que están fuera de su propia estructura de directorio (carpeta actual y abajo). Entonces, en la respuesta anterior, digamos que su estructura de directorios se ve así:

enter image description here

Donde ProjectX y ProjectY son directorios padre / hijo, y ProjectX hace referencia a A.dll, que a su vez hace referencia a B.dll, y B.dll está fuera de la estructura de directorios, como en un paquete Nuget en la raíz (Paquetes), luego A. dll se incluirá, pero B.dll no lo hará.

Me encontré con un problema muy similar. Al comstackr con Visual Studio 2010, el archivo DLL se incluyó en la carpeta bin . Pero al comstackr con MSBuild no se incluyó el archivo DLL de terceros.

Muy frustrante. La forma en que lo resolví fue incluir la referencia de NuGet al paquete en mi proyecto web, aunque no lo estoy usando directamente allí.

Tuve un problema similar hoy, y ciertamente esta no es la respuesta a su pregunta. Pero me gustaría informar a todos, y posiblemente proporcionar una chispa de visión.

Tengo una aplicación ASP.NET. El proceso de comstackción está configurado para limpiar y luego construir.

Tengo dos scripts de Jenkins CI . Uno para producción y uno para puesta en escena. Desplegué mi aplicación para la puesta en escena y todo funcionó bien. Implementado en producción y faltaba un archivo DLL al que se hizo referencia. Este archivo DLL estaba justo en la raíz del proyecto. No en ningún repository NuGet. La DLL estaba configurada para do not copy .

La secuencia de comandos de CI y la aplicación eran las mismas entre las dos implementaciones. Aún después de la limpieza e implementación en el entorno de ensayo, el archivo DLL fue reemplazado en la ubicación de despliegue de la aplicación ASP.NET ( bin/ ). Este no fue el caso para el entorno de producción.

Resulta que en una twig de pruebas agregué un paso al proceso de comstackción para copiar este archivo DLL al directorio bin . Ahora la parte que tomó un poco de tiempo para averiguarlo. El proceso de CI no se estaba limpiando solo. La DLL se dejó en el directorio de trabajo y se empaquetó accidentalmente con el archivo ASP.NET .zip. La twig de producción nunca tuvo el archivo DLL copiado de la misma manera y nunca lo implementó accidentalmente.

TLDR; Verifique y asegúrese de saber qué está haciendo su servidor de comstackción.

Incluir todos los archivos DLL referenciados de las referencias de proyectos en el proyecto del sitio web no siempre es una buena idea, especialmente cuando usa la dependency injections : su proyecto web solo desea agregar una referencia al archivo / proyecto DLL de interfaz, no a ninguna DLL concreta de implementación. archivo.

Porque si agrega una referencia directamente a un archivo / proyecto de implementación DLL, no puede evitar que su desarrollador llame a un “nuevo” en clases concretas del archivo / proyecto DLL de implementación en lugar de a través de la interfaz. También es que ha establecido un “código rígido” en su sitio web para usar la implementación.