La DLL dependiente no se copia en la carpeta de salida de compilación en Visual Studio

188

Tengo una solución de estudio visual. Tengo muchos proyectos en la solución. Hay un proyecto principal que actúa como la puesta en marcha y utiliza otros proyectos. Hay un proyecto que dice "ProjectX". Su referencia se agrega al proyecto principal. ProjectX hace referencia a otro .NET dll (digamos abc.dll) que no es parte de la solución.

Ahora este abc.dll debe copiarse en la carpeta bin / debug del proyecto principal, pero no se copia allí. ¿Por qué no se está copiando, alguna razón conocida?

Brij
fuente
Si no puede resolver esto, cópielo en su preconstrucción.
Dilshod
¿Cómo utiliza su 'ProjectX' en el proyecto principal? ¿
Cuál
Tuve el mismo problema y esta respuesta resolvió mi problema: stackoverflow.com/a/8213977/174469
Gordon Tucker
Hay una RestoreProjectStyle solución disponible . La idea es establecer <RestoreProjectStyle>PackageReference</RestoreProjectStyle>para cada proyecto de .Net Framework en la solución.
oleksa

Respuestas:

105

Descubrí que si ProjectX hacía referencia a abc.dll pero no usaba directamente ninguno de los tipos DEFINIDOS en abc.dll, entonces abc.dll NO se copiaría a la carpeta de salida principal. (Se copiaría en la carpeta de salida de ProjectX, para que sea más confuso).

Entonces, si no está utilizando explícitamente ninguno de los tipos de abc.dll en ninguna parte de ProjectX, coloque una declaración ficticia en algún lugar de uno de los archivos de ProjectX.

AbcDll.AnyClass dummy006; // this will be enough to cause the DLL to be copied

No necesita hacer esto para cada clase, solo una vez será suficiente para hacer que la copia de la DLL y todo funcione como se espera.

Anexo: Tenga en cuenta que esto puede funcionar para el modo de depuración, pero NO para la versión. Ver la respuesta de @ nvirth para más detalles.

Overlord Zurg
fuente
77
Esto parece un truco. Agregar la referencia al proyecto principal parece ser suficiente.
Mike K
3
ES un truco, pero como nos enseñaron las noticias actuales de CodeProject, ¡incluso los compiladores pueden estar equivocados!
Overlord Zurg
44
Qué locas pueden ser las cosas. @OverlordZurg su solución funcionó ya que tenía una referencia a la dll dependiente en mi XAML (WPF) y no copió la DLL al proyecto principal hasta que agregué una referencia ficticia simple como usted dijo ... Gracias de todos modos
Mohsen Afshin
55
@MohsenAfshin Tuve el mismo problema: estaba haciendo referencia a una DLL dependiente en XAML. Sin embargo, en lugar de declarar una variable ficticia, simplemente nombré el componente que estaba usando en XAML, y eso fue suficiente para hacer que se copiara su ensamblaje.
redcurry
55
@MikeK Agregarlo al proyecto principal (que en realidad no depende directamente de él) es un truco aún más grande, en mi opinión. Luego debe administrarlo en dos lugares ("administrar" como en la actualización o eliminación). Con este truco, al menos obtienes un buen error de tiempo de compilación que te recuerda que elimines este truco cuando eliminas la dependencia, y aún así solo necesitas actualizarlo en un solo lugar.
jpmc26
71

Solo una nota al margen de la respuesta del señor supremo Zurg.

He agregado la referencia ficticia de esta manera, y funcionó en modo de depuración:

public class DummyClass
{
    private static void Dummy()
    {
        var dummy = typeof(AbcDll.AnyClass);
    }
}

Pero en el modo Release, el dll dependiente aún no se copió.
Esto funcionó sin embargo:

public class DummyClass
{
    private static void Dummy()
    {
        Action<Type> noop = _ => {};
        var dummy = typeof(AbcDll.AnyClass);
        noop(dummy);
    }
}

Esta información en realidad me costó horas averiguarlo, así que pensé en compartirlo.

nacimiento
fuente
77
en el modo de lanzamiento, el optimizador supone que no se usa "ficticio", por lo que esta línea es innecesaria y debe eliminarse. pero cuando usa "ficticio" en el código, el optimizador no supone que sea innecesario.
Yucel
1
esto no funciona para mí.AbcDll.AnyClass todavía no se copia a otro proyecto
Matthew Lock
3
Asegúrese de que AbcDll.AnyClassse utiliza como un campo público o propiedad en una clase pública, entonces funcionará. Si lo usa en un cuerpo de método como este, el compilador no lo ve . Retrasará la carga de este ensamblaje, no lo que desea que suceda.
John Leidegren
52

Sí, usted tendrá que establecer Copy Locala true. Sin embargo, estoy bastante seguro de que usted también necesitará de referencia que el montaje del proyecto principal y el conjunto Copy Localde trueasí - no solo se copian desde un ensamblado dependiente.

Puede acceder a la Copy Localpropiedad haciendo clic en el ensamblaje debajo Referencesy presionando F4.

Mike Perrenoud
fuente
2
@Brij, ¿se hace referencia al ensamblaje del proyecto principal en el que lo quieres? Como dije, estoy bastante seguro de que también necesita hacer referencia a ese proyecto, ya que los ensamblajes dependientes no se copian de esa manera. Si ese fuera el caso, no necesitaría agregar los ensamblajes a todos los proyectos relevantes al usar NuGet.
Mike Perrenoud
1
¿Cuál fue la conclusión aquí? Me parece que tiene razón: las referencias dependientes no se copian incluso si CopyLocal se establece en verdadero. ¿Cuál es la lógica detrás de eso?
mcmillab
29
@mcmillab, en resumen, Visual Studio no infiere dependencias de otros proyectos dependientes. Si el proyecto A hace referencia al proyecto B, el proyecto A necesitará tener todas las referencias del proyecto B. Funciona bien cuando todo lo que necesita el proyecto B son ensamblados .NET, pero si se trata de un ensamblaje de terceros, debe agregar la referencia a ambos proyectos.
Mike Perrenoud
12
@MichaelPerrenoud No creo que sea verdad. Si observa una salida detallada de MSBuild verá llamadas a ResolveAssemblyReference que dice que "incluye dependencias de segundo y enésimo orden". Esto también coincide con lo que veo en mis carpetas bin (se copian las dependencias n-ésima). El problema es que hay algunas advertencias sobre lo que se copia, principalmente alrededor del GAC y referencias indirectas (Agregar referencia a veces no es suficiente)
Jack Ukleja
2
Mi experiencia actual es que esto funcionará a excepción de las dependencias 'copiadas': el proyecto A.net hace referencia a archivos dlls externos de C ++ como archivos que son 'copiar siempre'. El proyecto B.net hace referencia al proyecto A. En la compilación, B / Debug incluye los dlls de C ++. Sin embargo, cuando construyo la Aplicación X, que hace referencia al Proyecto B, los dlls de C ++ a veces se copian (parece ser solo si realizo una Reconstrucción).
Benjol
34

Parece elegante cuando lo convierte en un atributo de ensamblaje

[AttributeUsage(AttributeTargets.Assembly)]
public class ForceAssemblyReference: Attribute
{        
    public ForceAssemblyReference(Type forcedType)
    {
        //not sure if these two lines are required since 
        //the type is passed to constructor as parameter, 
        //thus effectively being used
        Action<Type> noop = _ => { };
        noop(forcedType);
    }
}

El uso será:

[assembly: ForceAssemblyReference(typeof(AbcDll.AnyClass))]
Aryéh Radlé
fuente
Gracias, pero para mí esto solo hace algo cuando agrego el atributo de ensamblaje a la dependencia (Proyecto X), que ya hace referencia a AbcDll.AnyClass. Y luego, no hace más de lo normal, donde copia el AbcDll en el directorio de salida de la dependencia. Todavía no lo copia en la salida del proyecto dependiente principal. Y no puedo agregar el atributo al ensamblado dependiente a menos que también agregue una referencia a AbcDll. Cuando hago eso, AbcDll ya se copia sin el atributo.
JS
25

Me encontré con este mismo problema. Información básica: antes de construir, había agregado un nuevo Proyecto X a la solución. El proyecto Y dependía del proyecto X y el proyecto A, B, C dependía del proyecto Y.

Los errores de compilación fueron que los dlls del Proyecto A, B, C, Y y X no se pudieron encontrar.

La causa principal fue que el Proyecto X recién creado apuntó a .NET 4.5 mientras que el resto de los proyectos de solución apuntaron a .NET 4.5.1. El Proyecto X no se construyó, lo que provocó que el resto de los Proyectos tampoco.

Asegúrese de que los proyectos recién agregados tengan como destino la misma versión .NET que el resto de la solución.

Darren Alfonso
fuente
1
Los proyectos referenciados pueden ser una versión anterior de .NET. Puedo hacer referencia a un proyecto creado para .NET 4 por un proyecto creado para .NET 4.5.
redcurry
18

No estoy seguro de si esto ayuda, pero para mí, muchas veces hago referencia a una DLL (que, por supuesto, la agrega automáticamente a la carpeta bin). Sin embargo, esa DLL podría necesitar DLL adicionales (dependiendo de las funciones que esté usando). NO quiero hacer referencia a aquellos en mi proyecto porque simplemente necesitan terminar en la misma carpeta que la DLL que estoy usando.

Lo logro en Visual Studio al "Agregar un archivo existente". Debería poder agregarlo en cualquier lugar, excepto la carpeta Add_data. personalmente solo lo agrego a la raíz.

Luego cambie las propiedades de ese archivo a ...

Acción de compilación = Ninguna (tener esto configurado en algo como Contenido realmente copia la versión "raíz" a la raíz, más una copia en el Bin).

Copiar a la carpeta de salida = Copiar si es más reciente (Básicamente lo coloca en la carpeta BIN solo si falta, pero no lo hace después de eso)

Cuando publico ... mi DLL agregado solo existe en la carpeta BIN y en ningún otro lugar en la ubicación de publicación (que es lo que quiero).

da_jokker
fuente
10

También puede verificar para asegurarse de que las DLL que está buscando no estén incluidas en el GAC. Creo que Visual Studio está siendo inteligente al no copiar esos archivos si ya existe en el GAC en la máquina de compilación.

Recientemente me encontré en esta situación en la que había estado probando un paquete SSIS que necesitaba ensamblajes para existir en el GAC. Desde entonces lo había olvidado y me preguntaba por qué esas DLL no salían durante una compilación.

Para verificar qué hay en el GAC (desde un símbolo del sistema de Visual Studio Developer):

gacutil -l

O salida a un archivo para que sea más fácil de leer:

gacutil -l > output.txt
notepad.exe output.txt

Para eliminar un ensamblaje:

gacutil -u MyProjectAssemblyName

También debo tener en cuenta que, una vez que eliminé los archivos del GAC, se enviaron correctamente al directorio \ bin después de una compilación (incluso para ensamblados a los que no se hizo referencia directamente en el proyecto raíz). Esto fue en Visual Studio 2013 Update 5.

Brett
fuente
Gracias, tiene razón, MSBuild no copiará dll a la carpeta de salida si los encontró en el GAC.
John-Philip
3

En mi caso, fue lo más estúpido, causado por un comportamiento predeterminado de TFS / VS con el que no estoy de acuerdo.

Como agregar el dll como referencia al proyecto principal no funcionó, decidí agregarlo como un "Elemento existente", con Copiar local = Siempre. Incluso entonces el archivo no estaba allí.

Resulta que, aunque el archivo está presente en la Solución VS y todo lo compilado tanto localmente como en el servidor, VS / TFS no agregó realmente agrega el archivo al control de origen. No se incluyó en absoluto en los "Cambios pendientes". Tuve que ir manualmente al Explorador de control de código fuente y hacer clic explícitamente en el icono "Agregar elementos a la carpeta".

Estúpido porque llevo 15 años desarrollándome en VS. Me he encontrado con esto antes, simplemente no lo recordaba y de alguna manera lo extrañé porque todo aún se compiló porque el archivo era una referencia regular, pero el archivo que se agregó como Elemento existente no se estaba copiando porque no existía en El servidor de control de origen.

Espero que esto le ahorre tiempo a alguien, ya que perdí 2 días de mi vida por esto.

GR7
fuente
1
No puedo agradecerte lo suficiente ... me ahorraste mucho tiempo. Esta fue la solución para mí. También expuso el problema raíz, la DLL que agregué como referencia coincidía con un gitignorepatrón, por lo que al agregarla como referencia no se agregó al proyecto. ¡DEBE agregar manualmente el archivo al control de origen!
Mattkwish
2

Este es un pequeño ajuste en el ejemplo de nvirth

internal class DummyClass
{
    private static void Dummy()
    {
        Noop(typeof(AbcDll.AnyClass));
    }
    private static void Noop(Type _) { }
}
maca134
fuente
2

Lo agregaría a los eventos Postbuild para copiar las bibliotecas necesarias en los directorios de salida. Algo así como XCopy pathtolibraries targetdirectory

Puede encontrarlos en las propiedades del proyecto -> Crear eventos.

chethan jain
fuente
Esto funcionó para mí, y creo que esta es la mejor respuesta. La solución de referencia ficticia funciona, pero es un truco, mientras que una regla posterior a la compilación es una forma limpia de lograr el mismo resultado.
Kevin Fichter
2

Problema:

Se encontró con un problema similar para una DLL de paquete NuGet (Newtonsoft.json.dll) donde la salida de compilación no incluye la DLL referenciada. Pero la compilación va bien.

Reparar:

Revisa tus proyectos en un editor de texto y busca referencias con etiquetas en ellos. Como verdadero o falso. "Privado" es sinónimo de "Copiar local". En algún lugar de las acciones, MSBuild está tomando la tarea de localizar dependencias, encuentra su dependencia en otro lugar y decide no copiarla.

Entonces, revise cada archivo .csproj / .vbproj y elimine las etiquetas manualmente. Reconstruir, y todo funciona tanto en Visual Studio como en MSBuild. Una vez que tenga eso funcionando, puede volver y actualizar el lugar donde cree que debe estar.

Referencia:

https://www.paraesthesia.com/archive/2008/02/13/what-to-do-if-copy-local-works-in-vs-but.aspx/

Nkl Kumar
fuente
1

NO HAY NECESIDAD DE DUMMY IN CODE
Solo:

agregar una referencia al proyecto ejecutable

o / y asegúrese de que la referencia en el proyecto ejecutable se haya "Copy Local"establecido en TRUE(que fue mi " error ") parece que esto "sobrescribió" la configuración en el proyecto de biblioteca referenciado base ...

Cadburry
fuente
1

Si hace clic con el botón derecho en el ensamblaje al que se hace referencia, verá una propiedad llamada Copiar local . Si Copiar local se establece en verdadero, el ensamblaje debe incluirse en el contenedor. Sin embargo , parece haber un problema con Visual Studio, que a veces no incluye el dll referenciado en la carpeta bin ... esta es la solución que funcionó para mí:

ingrese la descripción de la imagen aquí

Hooman Bahreini
fuente
1
Copy Loal fue deshabilitado, esto ayudó a stackoverflow.com/questions/15526491/…
codemirror
1

TLDR; Visual Studio 2019 puede simplemente necesitar un reinicio.

Encontré esta situación usando proyectos basados ​​en el proyecto Microsoft.NET.Sdk.

<Project Sdk="Microsoft.NET.Sdk">

Específicamente:

  • Project1: objetivos .netstandard2.1
    • referencias a Microsoft.Extensions.Logging.Consoletravés de Nuget
  • Project2: objetivos .netstandard2.1
    • referencias a Project1través de una referencia de proyecto
  • Project2Tests: objetivos .netcoreapp3.1
    • referencias a Project2través de una referencia de proyecto

En la ejecución de la prueba, recibí el mensaje de error que indica que Microsoft.Extensions.Logging.Consoleno se pudo encontrar, y de hecho no estaba en el directorio de salida.

Decidí evitar el problema mediante la adición Microsoft.Extensions.Logging.Consolea Project2, sólo para descubrir que Nuget Administrador de Visual Studio no enumeró Microsoft.Extensions.Logging.Consolecomo instalados en Project1, a pesar de su presencia en el Project1.csprojarchivo.

Un simple apagado y reinicio de Visual Studio resolvió el problema sin la necesidad de agregar una referencia adicional. Quizás esto le ahorrará a alguien 45 minutos de pérdida de productividad :-)

Eric Patrick
fuente
En realidad, reinicié toda la PC en mi forma de probar cosas, pero funcionó para mí
Noman_1
0

Puede configurar tanto el proyecto principal como la ruta de salida de compilación de ProjectX en la misma carpeta, luego puede obtener todos los archivos DLL que necesita en esa carpeta.

YantingChen
fuente
0

Asegúrese de que el dll dependiente utilizado por usted no tenga un marco .net objetivo más alto que el marco .net objetivo de la aplicación de su proyecto.

Puede verificar esto seleccionando su proyecto, luego presione ALT + ENTRAR, luego seleccione Aplicación desde el lado izquierdo y luego seleccione Marco de destino de su proyecto.

Supongamos que el dll Target Framework = 4.0 dependiente y el dll Target Framework = 3.5 de la aplicación cambian esto a 4.0

¡Gracias!

Manish Jain
fuente
0

Además de los comunes anteriores, tenía que publicar una solución multiproyecto. Aparentemente, algunos archivos se dirigen a diferentes marcos.

Entonces mi solución: Propiedades> Versión específica (Falso)

RicL
fuente
0

Agregue la DLL como un elemento existente a uno de los proyectos y se debe ordenar

abhijithkarkal
fuente
0

VS2019 V16.6.3

Para mí, el problema era de alguna manera que el archivo .proj principal terminaba con una entrada como esta para el proyecto cuya DLL no se estaba copiando en la carpeta bin del proyecto principal:

<ProjectReference Include="Project B.csproj">
  <Project>{blah blah}</Project>
  <Name>Project B</Name>
  <Private>True</Private>
</ProjectReference>

Eliminé manualmente la línea <Private>True</Private>y la DLL se copió a la carpeta bin del proyecto principal en cada compilación del proyecto principal.

Si va a la referencia del proyecto problemático en la carpeta de referencias del proyecto principal, haga clic en él y vea las propiedades hay una configuración "Copiar local". La etiqueta privada equivale a esta configuración, pero para mí, por alguna razón, cambiar la copia local no tuvo efecto en la etiqueta privada en el archivo .proj.

Molesto, no cambié el valor local de la copia para la referencia, no tengo idea de cómo se configuró de esa manera y otro día desperdicié la búsqueda de un estúpido problema con VS.

Gracias a todas las otras respuestas que ayudaron a ubicarme en la causa.

HTH

Richard Moore
fuente