2010-03-23 30 views
19

Tengo este extraño problema que no puedo manejar. Una clase en el modelo de mi proyecto mvp diseñado como singleton causa una InvalidCastException. La fuente de error se encuentra en esta línea de código donde el objeto deserializado se asigna a la variable de instancia de la clase: engineObject = (ENGINE)xSerializer.Deserialize(str); Ocurre cada vez que intento agregar uno de mis UserControls a un formulario oa una UC diferente. Todos mis UC tienen un presentador especial que accede a la variable de instancia antes mencionada de la clase singleton. Esto es lo que obtengo cuando trato de agregar un UC en alguna parte:InvalidCastException para dos Objetos del mismo tipo

'System.TypeInitializationException: el inicializador de tipo para' MVP.Model.EngineData 'lanzó una excepción. ----> System.InvalidCastException: [A] El motor no se puede convertir a [B] Engine. El tipo A se origina de 'MVP.Model, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null' en el contexto 'LoadNeither' en la ubicación '[...] \ AppData \ Roaming \ Microsoft \ VisualStudio \ 9.0 \ ProjectAssemblies \ uankw1hh01 \ MVP.Model.dll '. El tipo B se origina de 'MVP.Model, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null' en el contexto 'LoadNeither' en la ubicación '[...] \ AppData \ Roaming \ Microsoft \ VisualStudio \ 9.0 \ ProjectAssemblies \ u_hge2de01 \ MVP.Model.dll '...

¿De alguna manera tengo dos ensamblados y no se accede desde mi carpeta de proyecto, sino desde una carpeta VS temp? Busqué en Google y solo encontré esto: IronPython Exception: [A]Person cannot be cast to [B]Person. Hay una solución ofrecida, pero primero se trata de IronPhyton y, en segundo lugar, ¿no sé dónde usarla en mi proyecto?

Sería genial, si u me podría ayudar a cabo aquí :-) THX

+0

cualquier solución ?? – Kiquenet

+0

Consulte http://stackoverflow.com/questions/23255892/how-to-reproduce-invalidcastexception-when-binding-to-an-assembly-in-the-loadfro/23255893#23255893 –

Respuesta

16

Los tipos son per-montaje; si tiene el "mismo" conjunto cargado dos veces, los tipos de cada "copia" del ensamblaje no se consideran del mismo tipo.

Estos problemas normalmente aparecen cuando los dos ensamblajes están en los contextos Load y LoadFrom. Ver

Difference between LoadFile and LoadFrom with .NET Assemblies?

y el enlace al blog de suzcook para más detalles sobre esta cuestión.

Además, considere usar el visor de registro de fusión para ayudar a diagnosticar el problema.

http://msdn.microsoft.com/en-us/library/e74a18c4%28VS.71%29.aspx

+0

hey eric, antes que nada: Gracias !!! usted es el primero en darme más sugerencias y ayuda en este caso. He revisado rápidamente los artículos (y los leeré nuevamente), pero ya tengo una pregunta: no estoy cargando ningún ensamblaje yo solo en el código. Solo estoy haciendo referencia a proyectos y luego agrego una UC con la ayuda del diseñador a una UC o Formulario diferente. Entonces mi pregunta es, ¿dónde debería comenzar a buscar fallas de carga ya que el IDE se ocupa de todos los procesos de carga? – LLEA

+0

He intentado usar el visor de registro de fusión, pero no pude ver nada (muy probablemente porque no lo utilicé correctamente). Además de eso, una vez más, ¿qué tan útil es esta herramienta ya que mis fallas tienen lugar antes del tiempo de ejecución? – LLEA

2

Mi caso particular - biblioteca de clases que se hace referencia en la aplicación web se renombró y reconstruido. La versión anterior de la biblioteca todavía estaba en la carpeta bin bajo el nombre anterior. El marco carga lo que sea en la carpeta bin (ambas bibliotecas) y emite este error. Ocurre no solo cuando los ensamblajes se cargan de forma explícita. La solución obvia en mi caso es limpiar la carpeta bin.

+0

Tan enojado que no lo busqué en Google antes de pasar 2 horas. No tuve que perder la depuración y solución de problemas para encontrar la línea de código que desencadena esta excepción. Una vez que encontré la línea de código, estaba lanzando una excepción sin quedar atrapado en Try/Catch ... Estaba TAN confuso. Me alegro de haber encontrado tu respuesta. Gracias @ M-Kay –

1

Mi situación implicó dos copias de la misma dll. Uno estaba en la carpeta bin y el otro en una subcarpeta de la misma carpeta bin. Ambos fueron cargados, sorprendentemente algunas cosas funcionaban bien, pero algunas cosas no lo hicieron y fue entonces cuando apareció este mensaje de error:

System.InvalidOperationException; There was an error generating the XML document.; Source: System.Xml; TargetSite: Void Serialize(System.Xml.XmlWriter, System.Object, System.Xml.Serialization.XmlSerializerNamespaces, System.String, System.String); 

Ocultos en esta era la siguiente excepción interna (esto tenía que ver con Microsoft Dynamics CRM 4.0, pero podría relacionarse con nada)

System.InvalidCastException; [A]XXX.CRMCustomCode.YYY.CreateCompanyRequest cannot be cast to [B]XXX.CRMCustomCode.YYY.CreateCompanyRequest. Type A originates from 'XXX.CRMCustomCode, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'LoadFrom' at location 'C:\Program Files\Microsoft CRM\Server\bin\assembly\XXX.CRMCustomCode.dll'. Type B originates from 'XXX.CRMCustomCode, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location 'C:\Program Files\Microsoft CRM\Server\bin\XXX.CRMCustomCode.dll'.; 

simplemente suprime la DLL duplicado (en C: \ archivos de programa \ Microsoft CRM \ Server \ bin) y el error fue.

1

A juzgar por el contexto en el que se está cargando el ensamblaje (el contexto es "LoadNeither"), algunos desarrolladores pueden hacer algo como cargar un ensamblaje que se haya empaquetado internamente como recurso con su aplicación. Si hace esto, usará el controlador de eventos AppDomain.CurrentDomain.AssemblyResolve, para que su aplicación pueda especificar dónde debe obtener .NET cualquier ensamblado particular que necesite.

Mi respuesta no explicará las maquinaciones de cómo hacerlo, pero lo menciono porque este proceso llevó directamente al mismo error exacto encontrado por el cartel original. Como Eric Lippert menciona, los tipos son por ensamblaje. Por lo tanto, si carga un ensamblaje individual más de una vez, la misma clase definida aparecerá como diferentes clases, aunque la inspección visual muestre que parecen ser las mismas.

Hemos visto casos en los que .NET llamará al ResolveEventHandler más de una vez para la misma DLL. No estoy seguro de por qué .NET a veces hace esto (sucedió en algunas máquinas, pero no en todas). Pero para resolver el problema, necesitábamos mantener una lista global de identificadores para los ensamblados cargados, de modo que si .NET deseaba cargar el ensamblado nuevamente, devolviéramos un identificador al mismo ensamblado que se cargó originalmente, en lugar de cargar otra copia en la memoria .

He incluido el código que nos causó el problema y notas sobre cómo manejarlo correctamente.

public void AppStartup (object sender, StartupEventArgs e) 
    { 
     AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); 
    } 

    public System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 
    { 
     string dllName = args.Name.Contains(',') ? args.Name.Substring(0, args.Name.IndexOf(',')) : args.Name.Replace(".dll", ""); 
     dllName = dllName.Replace(".", "_"); 

     if (dllName.EndsWith("_resources")) return null; 
     System.Resources.ResourceManager rm = new System.Resources.ResourceManager(GetType().Namespace + ".Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly()); 
     byte[] bytes = null; 
     try 
     { 
      bytes = (byte[])rm.GetObject(dllName); 
     } 
     catch (Exception ex) 
     { 
     } 
     if (bytes != null) 
     { 
      // the following call will return a newly loaded assembly 
      // every time it is called 
      // if this function is called more than once for the same 
      // assembly, you'll load more than one copy into memory 
      // this can cause the InvalidCastException 
      // instead of doing this, you keep a global list of loaded 
      // assemblies, and return the previously loaded assembly 
      // handle, instead of loading it again 
      return System.Reflection.Assembly.Load(bytes); 
     } 
     return null; 
    } 
+0

Tu solución me ayudó a descubrir que estaba cargando un ensamblaje más de una vez y obteniendo la excepción InvalidCastException "LoadNeither". Muchas gracias. –

Cuestiones relacionadas