2010-09-26 12 views
6

Tengo un problema con la deserialización XML que me desconcierta.¿Por qué XmlSerializer.Deserialize arroja una excepción System.IO.FileLoadException?

Estoy construyendo una aplicación que admite la personalización local de los diversos servicios que utiliza. Implementé una clase abstracta ServiceLocator cuyos métodos devuelven varios objetos. Cada instalación personalizada es responsable de implementar una subclase de esto y proporcionar implementaciones de esos métodos. La carne de esta clase es el siguiente:

public abstract class ServiceLocator 
{ 
    public static void Initialize(string customFeaturesPath) 
    { 
     Assembly a = Assembly.LoadFrom(customFeaturesPath); 
     Type t = a.GetExportedTypes() 
      .AsEnumerable() 
      .Where(x => x.IsSubclassOf(typeof (ServiceLocator))) 
      .First(); 
     Default = (ServiceLocator)a.CreateInstance(t.FullName); 
    } 

    public static ServiceLocator Default { get; private set; } 

    public abstract DefaultValuesContainer CreateDefaultValuesContainer(); 
} 

Esto funciona muy bien: me sale el camino a la costumbre operaciones de ensamblaje desde el archivo de configuración de la aplicación, el programa llama Initialize, y luego la aplicación puede llamar a los diversos métodos en ServiceLocator.Default y devuelven las implementaciones personalizadas apropiadas de los servicios.

Uno de estos servicios es un DefaultValuesContainer. Este es un objeto simple que expone propiedades cuyos valores deben persistir en un archivo de configuración de usuario. La idea es que puedo serializar este objeto en una configuración de usuario única del tipo string. Es un archivo de configuración de usuario que no querrás editar manualmente, pero estoy de acuerdo con eso.

Aquí hay una aplicación concreta de ServiceLocator.CreateDefaultValuesContainer:

protected override DefaultValuesContainer CreateDefaultValuesContainer(string serializedXml) 
{ 
    DefaultValuesContainer c = new ClientDefaultValuesContainer(); 

    if (string.IsNullOrEmpty(serializedXml)) 
    { 
     return c; 
    } 
    XmlSerializer x = new XmlSerializer(c.GetType()); 
    return (DefaultValuesContainer) x.Deserialize(new StringReader(serializedXml)); 
} 

Ahora aquí es la cosa.

He construido pruebas de unidad para esto usando NUnit. Cuando ejecuto las pruebas en la clase de dispositivo de prueba que ejercita las características personalizadas del cliente, funcionan. Cuando corro todo el conjunto de pruebas, la última línea del método anterior lanza esta excepción:

System.InvalidOperationException : There is an error in XML document (0, 0). 
    ----> System.IO.FileLoadException : Could not load file or assembly 'ClientCustomFeatures, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. Invalid pointer (Exception from HRESULT: 0x80004003 (E_POINTER)) 
    ----> System.ArgumentNullException : Value cannot be null. 
Parameter name: path1 

estoy un poco desconcertado en cuanto a por qué. El método SetUp aún se ejecuta y ServiceLocator.Default todavía devuelve un objeto del tipo ClientServiceLocator, lo que significa que ha cargado el ensamblaje ClientCustomFeatures. De hecho, el mismo método que arroja la excepción está en el conjunto que me dicen que no se puede cargar.

¿Qué está haciendo XmlSerializer haciendo aquí? ¿Por qué está intentando cargar un ensamblaje que ya está cargado? ¿Qué diablos significa "Puntero Inválido"? Y, sobre todo, ¿cómo debo depurar algo como esto?

+2

No conozco ese error específico, pero tenga en cuenta que XmlSerializer usa generación de código y compilación dinámica, por lo que está intentando crear un ensamblado * nuevo * que haga referencia a los que necesita. Parece que este nuevo ensamblaje (generado) no está satisfecho con la referencia. ¿Están (por ejemplo) todos los tipos necesarios involucrados 'públicos'? –

+3

Es seguro un problema de referencia. Abra ClientCustomFeatures.dll en el reflector y busque cualquier referencia que no tenga. –

Respuesta

0

He tenido problemas con el cargador de ensamblaje (¿Fusion?) Cuando un ensamblaje carga otro ensamblaje que tiene referencias (no GAC). YourDLL.XmlSerializers.dll podría ser uno de estos conjuntos. Intente desactivar la opción de Visual Studio para generar automáticamente un conjunto de serialización XML (opciones de proyecto); esto eliminará el ensamblaje adicional (y, por lo tanto, la dependencia de este).

0

Fusión Visor de registro de

para ayudar a diagnosticar problemas de carga de montaje como estos, echar un vistazo a la Fusion Log Viewer (También conocido como Fuslogvw.exe).

Fusion == el componente .NET que localiza y carga ensamblajes.

0

tratar de sustituir la línea:

XmlSerializer x = new XmlSerializer(c.GetType()); 

con:

XmlSerializer x = new XmlSerializer(c.GetType(), new Type[] { typeof(DefaultValuesContainer), typeof(ClientDefaultValuesContainer) }); 
1

Si el ensamblado personalizado no sabe dónde cargar el ensamblado que contiene la clase ClientCustomFeatures, esto sucederá. Esto ocurre cuando ha implementado su ensamblaje personalizado en una ubicación que no está en la ruta de su ensamblaje principal y su ensamblaje principal no está en el gac. Por lo tanto, si los asseblies personalizados se cargan desde los subdirectorios de su ensamblaje principal, esto debería desaparecer. Sin embargo, si se encuentran en lugares arbitrarios, tendrá un problema porque deben cargar su ensamblaje principal ya que necesitan acceso al tipo ClientCustomFeatures.

+0

Bueno, todos los ensamblajes están en el mismo directorio, así que no creo que ese sea el caso aquí. –

+1

Hola Robert, eche un vistazo a este sitio: http://msdn.microsoft.com/en-us/library/aa302290.aspx Tiene una serie de excelentes ideas para la resolución de problemas que se refieren al problema que está obteniendo y las razones por las cuales podría estar ocurriendo. También hay un enlace a una herramienta que debería ayudarlo a solucionarlo. Como no tenemos acceso a todo tu código, no podemos hacer esto por ti, pero me gustaría ser muy interesante para saber cuál es el resultado de esta pequeña aventura :) Deberás consultar las "Excepciones en el constructor" "sección – Kell

+0

Solo por algo: NUnit se ejecuta en una ubicación de caché temporal y puede no tener los privilegios apropiados para cargar todos los ensamblados y generar clases. Pero lea la URL anterior, tiene muchas más rutas de investigación o usted. – Kell

Cuestiones relacionadas