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?
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'? –
Es seguro un problema de referencia. Abra ClientCustomFeatures.dll en el reflector y busque cualquier referencia que no tenga. –