válida una standard signatura seguro referencia puede para nombre net necesita hacer este error ensamblado con como cargar axinterop archivo acropdflib c# serialization .net-assembly

c# - una - no se puede cargar el archivo o ensamblado restsharp



Cómo reproducir InvalidCastException cuando se vincula a un ensamblado en el contexto LoadFrom (1)

En .NET CLR Notes de Suzanne Cook, ella habla sobre los peligros del contexto "LoadFrom". Específicamente,

  • Si un ensamblaje de contexto de carga intenta cargar este ensamblado por el nombre para mostrar, no se encontrará por defecto (por ejemplo, cuando mscorlib.dll deserializa este ensamblaje)
  • Peor aún, un ensamblado con la misma identidad pero en una ruta diferente podría encontrarse en la ruta de exploración, lo que ocasionaría una InvalidCastException, MissingMethodException o un comportamiento de método inesperado más adelante.

¿Cómo se reproduce este comportamiento con la deserialización, pero sin cargar explícitamente dos versiones diferentes del ensamblaje?


Creé una aplicación de consola, A.exe, que carga indirectamente (a través de `Assembly.LoadFrom) y llama (mediante reflexión) el código de una biblioteca de clases, B.dll.

  • A.exe no tiene (necesariamente) una referencia a B.dll, pero B.dll debe existir en el mismo directorio que A.exe
  • Se debe colocar una copia de B.dll en otro directorio (aquí he usado el subdirectorio llamado LoadFrom), esta es la ubicación en la que usaremos Assembly.LoadFrom .

A.exe

class Program { static void Main(string[] args) { // I have a post build step that copies the B.dll to this sub directory. // but the B.dll also lives in the main directory alongside the exe: // mkdir LoadFrom // copy B.dll LoadFrom // var loadFromAssembly = Assembly.LoadFrom(@"./LoadFrom/B.dll"); var mySerializableType = loadFromAssembly.GetType("B.MySerializable"); object mySerializableObject = Activator.CreateInstance(mySerializableType); var copyMeBySerializationMethodInfo = mySerializableType.GetMethod("CopyMeBySerialization"); try { copyMeBySerializationMethodInfo.Invoke(mySerializableObject, null); } catch (TargetInvocationException tie) { Console.WriteLine(tie.InnerException.ToString()); } Console.ReadKey(); } }

B.dll

namespace B { [Serializable] public class MySerializable { public MySerializable CopyMeBySerialization() { return DeepClone(this); } private static T DeepClone<T>(T obj) { using (var ms = new MemoryStream()) { var formatter = new BinaryFormatter(); formatter.Serialize(ms, obj); ms.Position = 0; return (T)formatter.Deserialize(ms); } } } }

Salida

System.InvalidCastException: [A]B.MySerializable cannot be cast to [B]B.MySerializable. Type A originates from ''B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'' in the context ''Default'' at location ''c:/Dev/bin/Debug/B.dll''. Type B originates from ''B, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'' in the context ''LoadFrom'' at location ''c:/Dev/bin/Debug/LoadFrom/B.dll''. at B.MySerializable.DeepClone[T](T obj) at B.MySerializable.CopyMeBySerialization()

Esto es lo que está sucediendo:

  • Cuando se realiza la llamada a formatter.Deserialize(ms) , utiliza la información almacenada en MemoryStream para determinar qué tipo de objeto necesita crear (y qué ensamblaje necesita para crear ese objeto).
  • Encuentra que necesita B.dll e intenta cargarlo (desde el contexto predeterminado "Cargar").
  • El B.dll cargado actualmente no se encuentra (porque se cargó en el contexto "LoadFrom").
  • Por lo tanto, se intenta encontrar B.dll en las ubicaciones habituales, se encuentra en el directorio ApplicationBase y se carga.
  • Todos los tipos en este B.dll se consideran tipos diferentes a los de los otros B.dll. Por lo tanto, el molde en la expresión (T)formatter.Deserialize(ms) falla.

Notas adicionales:

  • Si el B.dll no hubiera existido en algún lugar donde A.exe pudiera encontrarlo usando Assembly.Load , entonces en lugar de una InvalidCastException , habría una SerializationException con el mensaje Imposible encontrar el ensamblado ''B, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null ''.
  • El mismo problema ocurre incluso con ensamblajes firmados, pero lo que es más alarmante con los ensamblados firmados es que puede cargar una versión diferente del ensamblado firmado. Es decir, si B.dll en el contexto "LoadFrom" es 1.0.0.0, pero el B.dll encontrado en el directorio principal es 2.0.0.0, el código de serialización todavía cargará la versión incorrecta B.dll para hacer la deserialización.
  • El código de DeepClone que he mostrado parece ser una de las formas más populares de hacer un clon profundo en un objeto. Ver: objetos de clonación profunda en C # .

Por lo tanto, desde cualquier código que se haya cargado en el contexto "LoadFrom", no se puede utilizar la deserialización con éxito (sin saltar a través de aros adicionales para permitir que el ensamblaje se cargue correctamente en el contexto "Cargar" predeterminado).