for - visual studio c# descargar
¿Usando 2 versiones diferentes de la misma dll? (3)
Al faltar una respuesta completa que se adapte a mis necesidades, decidí donar mi solución con la forma de AssemblyResolve
de usar dos archivos DLL y cargar el archivo relevante, usando la reflexión para resolver el tipo. Para esta demostración, creé dos dlls llamados MathFuncs
, intentar invocar su función Add.add
se resolverá en dos implementaciones diferentes. Para ver los diferentes resultados, cambie el número entero entre los valores 1 y 2:
public static int version = 1;
public static void Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += Program.CurrentDomain_AssemblyResolve;
version = 1;
Type a = Type.GetType("MathFuncs.Add, MathFuncs, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
MethodInfo methodInfo = a?.GetMethod("add");
object result = null;
if (methodInfo != null)
{
object[] parametersArray = new object[] {1, 2};
result = methodInfo.Invoke(Activator.CreateInstance(a, null), parametersArray);
}
if (result != null)
{
Console.WriteLine((int)result);
}
else
{
Console.WriteLine("failed");
}
Console.Read();
}
public static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
FileInfo fi = null;
if (version == 1)
{
fi = new FileInfo("C://Users//ohbitton//Desktop//MathFuncs//MathFuncs.dll");
}
else
{
fi = new FileInfo("C://Users//ohbitton//Desktop//MathFuncs2//MathFuncs.dll");
}
return Assembly.LoadFrom(fi.FullName);
}
Para obtener el nombre completo del espacio de nombres para Type.GetType
, puede usar powershell:
([system.reflection.assembly]::loadfile("C:/Users/ohbitton/Desktop/MathFuncs/MathFuncs.dll")).FullName
Me han dado 2 dlls pre-compilados:
Common.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL
Common.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL
Ejemplo de diferencias en API:
Y estoy tratando de cargar ambos en un solo proyecto para hacer algo como esto:
extern alias v10;
extern alias v20;
private static void UpgradeUser()
{
// Load old user
var userOld = new v10::Common.Data.UserData();
userOld.loadData("user.dat");
// Create new user
var userNew = new v20::Common.Data.UserData();
// Copy properties
userNew.FirstName = userOld._firstName;
userNew.LastName = userOld._lastName;
userNew.Age = userOld._age;
// Invoke method from v10 and v20 API
userOld.version();
userNew.DisplayVersion();
if (userNew.GetUserInfo() != userOld.getInfo())
{
throw new Exception("Discrepencies in upgrade ");
}
Console.WriteLine("Upgrade done!");
}
He configurado mis referencias de proyecto y app.config
a lo siguiente. También estoy copiando manualmente los dlls en mi carpeta de salida, coincidiendo con el appconfig hrefs
<!-- [Edited: see history for previous version] -->
<Reference Include="Common.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL">
<HintPath>libs/Common.Data.1_0_0_0.dll</HintPath>
<Aliases>v10</Aliases>
</Reference>
<Reference Include="Common.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL">
<HintPath>libs/Common.Data.2_0_0_0.dll</HintPath>
<Aliases>v20</Aliases>
</Reference>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Common.Data" publicKeyToken="f3b12eb6de839f43" culture="neutral" />
<codeBase version="1.0.0.0" href="libs/Common.Data.1_0_0_0.dll" />
<codeBase version="2.0.0.0" href="libs/Common.Data.2_0_0_0.dll" />
</dependentAssembly>
</assemblyBinding>
</runtime>
He llegado hasta aquí para construir con éxito.
Pero cuando intento ejecutarlo, obtengo una MissingMethodException
para UserData.loadData
.
He pasado por varias publicaciones de stackoverflow, msdn y artículos de codeproject, pero parece que no puedo hacer que funcione.
Enlace 1 , Enlace 2 , Enlace 3 , Enlace 4
Creo que me estoy perdiendo un paso importante, pero no puedo averiguar qué, y realmente podría necesitar algo de ayuda.
[Edit1]
He intentado usar las DLL por separado, y funcionan. (Se eliminó el desorden. Consulte el historial de versiones para capturas de pantalla)
[Edit2]
He intentado la propuesta de Mukesh Kumar y cambié mi app.config a:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Common.Data"
publicKeyToken="f3b12eb6de839f43"
culture="neutral" />
<bindingRedirect oldVersion="1.0.0.0"
newVersion="2.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
Pero todavía no funciona. Ahora estoy recibiendo FileNotFoundException
.
[Edit3]
Ok, estoy casi seguro de que <bindingRedirect>
no es correcto, y debería ser <codeBase>
lugar.
Intenté compilar desde el CLI:
csc Program.cs /reference:v10=libs/Common.Data.1_0_0_0.dll /reference:v20=libs/Common.Data.2_0_0_0.dll
Y funciona bien. Pude usar ambas API al mismo tiempo:
Pero cuando intento compilarlo desde Visual Studio, se queja de / reference, a pesar de que ya he especificado el alias de referencia:
The extern alias ''v10'' was not specified in a /reference option
He intentado modificar <Reference />
para incluir / excluir <SpecificVersion>True</SpecificVersion>
sin ningún efecto.
Encontré esta , donde la solución era eliminar y volver a agregar las rutas. Usando esa solución, Visual Studio compila bien, pero he vuelto a System.MissingMethodException
.
Se siente como que casi lo tengo, pero no del todo. ¿Cómo puedo hacer que Visual Studio se compile correctamente?
[Editar4]
He intentado el método de miguel, pero aún no funciona.
En este intento, he cambiado el nombre de las dlls a sus nombres originales y, en su lugar, las guardo en diferentes carpetas.
Luego actualicé app.config para hacer un bindingRedirect así como un código base.
Cuando lo MissingMethodException
.
No estaba seguro de lo que significaba 4- Find the and put in False
, así que probé todas las combinaciones de <Private>
, <SpecificVersion>
, así como la configuración de <Reference Include>
en FQN, pero ninguna de esas combinaciones funciona.
Al ver mi tercera edición, he logrado compilar y ejecutar la muestra correctamente (con mi nombre de dlls + app.config codebase hrefs) cuando se realiza a través de la CLI.
Mi problema ahora es, ¿cómo configuro mi csproj, para que se construya de la misma manera?
Debe usar un ensamblaje dependiente con bindingRedirect pero también necesita poner dlls en una carpeta diferente o guardar con un nombre diferente. Con esto hecho, necesitas poner lo siguiente en tu app.config:
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="myAssembly"
publicKeyToken="here token dll"
culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.0.0.0" newVersion="1.0.0.0" />
<bindingRedirect oldVersion="1.0.0.1-2.0.0.0" newVersion="2.0.0.0" />
<codeBase version="1.0.0.0" href="folder/namedll.dll" />
<codeBase version="2.0.0.0" href="folder/namedll.dll" />
</dependentAssembly>
</assemblyBinding>
Con este código debe compilarse y ejecutarse, pero a veces VS borra o sobrescribe el código en app.config cuando lo compila. Necesitas chequearlo en el archivo de configuración de la carpeta de compilación. Si esto tiene éxito, puede editar el archivo .csproj. Para esto debes hacer:
1- Descargar el proyecto afectado.
2- Clic derecho en proyecto.
3- Haga clic en Editar proyecto
4- Encuentra la propiedad<AutoGenerateBindingRedirects>
y<AutoGenerateBindingRedirects>
en False
5- Guardar cambios y recargar proyecto
Esto funciona para mi En mi proyecto, estoy usando dos versiones de Automapper.
Finalmente, otra solución es usar el evento de compilación AppDomain.CurrentDomain.AssemblyResolve
y cargar la dll específica.
Para eso, necesitas atrapar el evento:
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
public static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
//debug and check the name
if (args.Name == "MyDllName")
return Assembly.LoadFrom("c://pathdll/midllv1.dll")
else if(args.Name ="MyDllName2")
return Assembly.LoadFrom("c://pathdll/midllv2.dll");
else
return Assembly.LoadFrom("");
}
Trate de poner sus detalles de configuración como sigue.
<dependentAssembly>
<assemblyIdentity name="myAssembly"
publicKeyToken="32ab4ba45e0a69a1"
culture="neutral" />
<bindingRedirect oldVersion="1.0.0.0"
newVersion="2.0.0.0"/>
</dependentAssembly>
Aquí puede proporcionarle la versión anterior de dll y la nueva versión. Puedes seguir este article y también this .
Espero que esto te ayudará.