c# - sirve - Usando múltiples versiones de la misma DLL
quién creó c#? (5)
Me asignaron la tarea de crear un nuevo módulo para una aplicación y, por lo tanto, agregaré nuevas DLL al proyecto. Todo esto está bien y bien.
Sin embargo, en mis DLL me gustaría usar una nueva versión de una DLL externa (sobre la cual no tengo control). Si solo hago referencia a la nueva DLL y solo trabajo con esa, mi código funcionará, pero el código anterior dejará de funcionar.
Could not load file or assembly ''itextsharp, Version=5.0.6.0, Culture=neutral,
PublicKeyToken=8354ae6d2174ddca'' or one of its dependencies. The located assembly''s
manifest definition does not match the assembly reference. (Exception from HRESULT:
0x80131040)
He intentado un simple truco para cambiar el nombre de las DLL, pero al parecer eso fue un poco demasiado ingenuo de mi parte para pensar que funcionaría. He intentado usar los alias externos (definiéndolos en mis referencias), pero aún no sé cómo obtener dos archivos con el mismo nombre en una carpeta BIN ...
¿Qué tengo que hacer?
Otra opción viable es usar extern
, como se describe aquí:
http://blogs.msdn.com/b/abhinaba/archive/2005/11/30/498278.aspx
Puede cargar otra versión en un dominio de aplicación específico
Posiblemente demasiado detallado, pero aquí hay un artículo que demuestra el uso de AppDomains en una configuración útil y cómo funcionan:
http://msdn.microsoft.com/en-us/magazine/cc164072.aspx
En un sentido muy básico se reduce a este código de ejemplo:
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
...
static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (/*some condition*/)
return Assembly.LoadFrom("DifferentDllFolder//differentVersion.dll");
else
return Assembly.LoadFrom("");
}
Si la solución de AppDomains no es aplicable en su caso, está bajo presión de tiempo, tiene requisitos contradictorios (como si eso hubiera sucedido) y no le importa hacks ideados de manera ridícula:
- Descompilar la versión más reciente del conjunto utilizando la herramienta ildasm (parte del símbolo del sistema del desarrollador incluida con Visual Studio)
- Edite el archivo .il generado para buscar / reemplazar las referencias de espacio de nombres del ensamblaje. Usando el ejemplo citado, esto sería un cambio de itextsharp.X a itextsharp.new.X
- Del mismo modo, edite el valor para el atributo AssemblyTitleAttribute. Esto requiere traducir los caracteres ASCII a hexadecimal.
- Recompila el archivo .il usando ilasm
- Tenga en cuenta que esto puede necesitar repetirse para cualquier ensamblaje dependiente (por ejemplo, someassembly.core.whatever)
- Agregue los nuevos .dlls a su proyecto con un nombre diferente y haga referencia a ellos explícitamente (en lugar de a través de nuget o lo que sea)
Oye, no me mires así. Dije hackeado ridículamente ideado ...
Supongamos que tiene una estructura de proyecto de la siguiente manera:
... donde A
y B
son bibliotecas de clases, y C
es un proyecto de tipo ejecutable (como una prueba unitaria o un proyecto de consola).
Asumamos que la estructura de carpetas es así:
ABC.sln
A/A.csproj
A/...
B/B.csproj
B/...
C/C.csproj
C/...
lib/thirdparty4/thirdparty.dll
lib/thirdparty5/thirdparty.dll
Si intentáramos hacer una referencia ingenua a nuestros proyectos, tendríamos un problema: dos versiones de thirdparty.dll
se copiarán en la misma carpeta (el directorio de salida (es decir, bin) de C
). Necesitamos una manera para que C
copie ambas dlls en su directorio de salida y proporcione un mecanismo para hacer referencia a cualquiera de ellas.
Para resolver esto, modifiqué C.csproj
para que contenga lo siguiente:
<ItemGroup>
<Content Include="../lib/thirdparty4/thirdparty.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>thirdparty4/thirdparty.dll</Link>
</Content>
<Content Include="../lib/thirdparty5/thirdparty.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>thirdparty5/thirdparty.dll</Link>
</Content>
</ItemGroup>
Esto le indicará que cree tanto thirdparty4/thirdparty.dll
y thirdparty5/thirdparty.dll
en su directorio de salida.
Ahora, después de construir C
, su directorio de salida se ve así:
C/bin/Debug/A.dll
C/bin/Debug/B.dll
C/bin/Debug/C.dll
C/bin/Debug/thirdparty4/thirdparty.dll
C/bin/Debug/thirdparty5/thirdparty.dll
Para indicar a C
que use estas dos dlls, le agregué un archivo App.config
, con lo siguiente:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="thirdparty" culture="neutral" publicKeyToken="1234567890123445"/>
<bindingRedirect oldVersion="4.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
<codeBase version="4.0.0.0" href="thirdparty4/thirdparty.dll" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="thirdparty" culture="neutral" publicKeyToken="1234567890123445"/>
<bindingRedirect oldVersion="5.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
<codeBase version="5.0.0.0" href="thirdparty5/thirdparty.dll" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Esto le indicará al ensamblaje que, dependiendo de la versión que se necesite, use una DLL u otra, las cuales estarán disponibles dentro de las subcarpetas del directorio de salida. (Los elementos bindingRedirect son opcionales, pero puede usarlos si necesita un rango de revisiones para que esto se aplique).
También puede confiar en la redirección de enlace de ensamblaje para su ensamblaje con nombre seguro como se describe en http://msdn.microsoft.com/en-us/library/2fc472t2.aspx .
Solo tendría una versión del archivo (la última), y ambas referencias se resolverían.