c# - una - Las referencias de la biblioteca de clases no se copian en la carpeta bin del proyecto en ejecuciĆ³n
no se puede completar la operacion visual studio 2017 (3)
Explicación
Para un caso de ejemplo, digamos que tenemos el proyecto X, el conjunto A y el conjunto B. El conjunto A hace referencia al conjunto 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 conjunto A (por ejemplo, A. SomeFunction ()). Ahora, creas 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 trata de ser inteligente y solo trae referencias al proyecto Y que detecta como requerido por el proyecto X; hace esto para evitar la contaminación de referencia en el proyecto Y. El problema es que, dado que el proyecto X no contiene ningún código que use explícitamente el conjunto B (por ejemplo, B.SomeFunction ()), VS / MSBuild no detecta que B es necesario por X, y por lo tanto no lo copia en el directorio bin del proyecto Y; solo copia las asambleas X y A.
Solución
Tiene dos opciones para resolver este problema, las cuales darán como resultado que el ensamblaje B se copie al directorio bin del proyecto Y:
- Agregue una referencia al conjunto B en el proyecto Y.
- Agregue código falso a un archivo en el proyecto X que usa el ensamblaje B.
Personalmente prefiero la opción 2 por un par de razones.
- Si agrega otro proyecto en el futuro que hace referencia al proyecto X, no tendrá que recordar incluir también una referencia al conjunto B (como tendría que ver con la opción 1).
- Puede tener comentarios explícitos que indiquen por qué el código ficticio debe estar allí y no eliminarlo. Entonces, si alguien elimina el código por accidente (por ejemplo, con una herramienta de refactoría que busca el código no utilizado), puede ver fácilmente desde el control de la fuente que se necesita el código 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; verá que se eliminó una referencia del archivo .csproj.
Aquí hay una muestra del "código ficticio" que normalmente agrego cuando me encuentro con 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);
}
Tengo una biblioteca de clases que representa mi capa lógica. A esa biblioteca le he agregado un paquete nuget para Google.Apis.Analytics.v3: instaló el paquete y todas sus dependencias.
Tengo una aplicación de consola que usa esa biblioteca de clases lógicas (referencia regular). Todo está escrito y bien compilado.
El problema es que durante el tiempo de ejecución se produjo una excepción que no se encontró Google.Apis.dll. Esta DLL es una dependencia que se descargó con el nuget.
Al revisar las carpetas BIN, encontré que en la carpeta bin de la biblioteca de clases esta DLL estaba presente, pero no en la carpeta BIN de la aplicación de la consola (mientras que otras DLL relacionadas lo estaban). Esto significa que no todas las referencias se copiaron durante la compilación.
Busqué en línea y encontré todo tipo de soluciones que realmente no funcionaron (como editar manualmente el archivo del proyecto y eliminar una verdadera línea XML en esa definición de DLL).
Lo que terminé haciendo es agregar la misma biblioteca de nuget a mi aplicación de consola, funciona pero se siente un poco sucia y no como debería ser. Creo que la aplicación de la consola es el cliente que se supone que debe obtener sus servicios de esa biblioteca de clases lógicas, que debería saberlo sin preocuparse por el "cliente".
Además, esa aplicación de consola no es la única que va a usar ese servicio, también estoy planeando una aplicación web que usará esa funcionalidad, así que también tendré que agregar el mismo nuget a esa aplicación web. un poco desordenado ...
¿Se trata sólo de mí? ¿Es esa la forma correcta de hacerlo? Estaba pensando en escribir un proyecto de WCF para manejar esa funcionalidad, pero eso me parece una sobrecarga para la funcionalidad, y probablemente ralentice mi flujo de trabajo solo para mantener las cosas "más limpias" en mi opinión.
¿Lo estoy pensando demasiado?
Gracias
Si tiene la siguiente cadena de dependencia: Lib1 <- Lib2 <- MyApp
Versión TLDR: al no hacer suposiciones, el sistema de construcción evita introducir incertidumbre / comportamiento inesperado.
Cuando compile MyApp, Lib2 se copiará en el directorio bin de MyApp para usted, pero Lib1 no lo hará. Deberá agregar una referencia a Lib2 y Lib1 en MyApp para obtener los dlls de Lib1 en el directorio bin de MyApp (de lo contrario, obtendrá el error de tiempo de ejecución). Sería imposible (o quizás realmente difícil) identificar el conjunto exacto de archivos que terminan en el directorio bin de Lib2 que sería seguro y apropiado copiar en MyApp''s. Si el sistema de compilación hizo suposiciones de que todo en el directorio bin de Lib2 era seguro para MyApp, o si se hacía referencia implícitamente a Lib1, podría cambiar el comportamiento de MyApp involuntariamente.
Imagine una solución donde más de 1 proyecto depende de Lib2 pero uno de esos proyectos quiere cargar un archivo .dll adyacente utilizando Assembly.LoadFrom / Activator.CreateInstance / MEF / etc. (un plugin) y el otro no. Una operación de copia automática podría capturar Lib2 junto con el archivo dll del complemento y copiarlo en el primer y segundo directorio de compilación del proyecto (ya que está en el directorio bin de Lib2 como resultado de una operación de compilación). Esto cambiaría el comportamiento de la segunda aplicación.
Alternativamente, si era un poco más inteligente e hizo referencia implícitamente a Lib1 para usted cuando hizo referencia a Lib2 (y no solo copió el contenido del directorio bin), aún podría causar consecuencias no deseadas. ¿Qué pasaría si MyApp ya dependiera de Lib1, pero estaba usando una copia de GAC''d / ngen''d que era compatible con la que Lib2 requiere? Si agregar una referencia a Lib2 implícitamente creó una referencia a Lib1 para usted, eso podría cambiar qué Lib1 se cargó y cambiar el comportamiento en tiempo de ejecución de su aplicación. Tal vez podría detectar que ya hay una Lib1 en el directorio bin de MyApp y omitirla, pero luego se podría suponer que la Lib1 que ya está allí es la correcta. Tal vez sea un .dll obsoleto que espera ser borrado por una operación de limpieza y la sobrescritura fue el movimiento correcto.
NuGet resuelve el problema que está describiendo con las dependencias de paquetes. Si Lib1 y Lib2 tuvieran paquetes nuget y el paquete Lib2 dependiera del paquete Lib1, cuando agregue Lib2 a MyApp, también se agregará Lib1. Las dos dll de pacakges terminarían en el directorio bin de MyApp.
Lo mejor que puedes hacer es invertir un poco tu pensamiento. En lugar de pensar:
- Lib2 necesita una referencia a Lib1 para compilar, así que agregaré una referencia a Lib1
Pensar:
- MyApp necesita lib2. Lo que Lib2 necesita, necesito. Así que MyApp y Lib2 obtienen una referencia a Lib1.
Si tienes 10 de dlls, es más fácil hacer una copia con un evento postbuild:
xcopy "$(ProjectDir)bin/*.dll" $(SolutionDir)MyTargetProject/bin/" /y