Sto riscontrando un problema con la deserializzazione XML che mi sconcerta.Perché XmlSerializer.Deserialize genera un System.IO.FileLoadException?
Sto costruendo un'applicazione che supporta la personalizzazione locale di vari servizi che utilizza. Ho implementato una classe astratta ServiceLocator
i cui metodi restituiscono vari oggetti. Ogni installazione personalizzata è responsabile dell'implementazione di una sottoclasse di questo e fornisce implementazioni di tali metodi. La carne di questa classe si presenta così:
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();
}
Questo funziona bene: ho il percorso per il costume presenta assembly dal file di configurazione dell'applicazione, il programma chiama Initialize
, e quindi l'applicazione può chiamare i vari metodi su ServiceLocator.Default
e restituiscono le implementazioni personalizzate appropriate dei servizi.
Uno di questi servizi è uno DefaultValuesContainer
. Questo è un oggetto semplice che espone le proprietà i cui valori devono essere mantenuti in un file di impostazioni utente. L'idea è che posso serializzare questo oggetto in una singola impostazione utente di tipo string
. È un file di impostazioni utente che non si desidera modificare manualmente, ma mi piace.
Ecco una concreta attuazione di 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));
}
Ora ecco la cosa.
Ho realizzato test di unità per questo utilizzando NUnit. Quando eseguo i test nella classe di test che esercita le funzioni personalizzate del client, funzionano. Quando eseguo l'intera suite di test, l'ultima riga del metodo di cui sopra genera questa eccezione:
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
Sono un po 'perplesso sul perché. Il metodo SetUp
viene ancora eseguito e ServiceLocator.Default
restituisce ancora un oggetto di tipo ClientServiceLocator
, che significa che ha caricato l'assembly ClientCustomFeatures
. In effetti, lo stesso metodo che lancia l'eccezione è nell'assembly che mi viene detto che non può essere caricato.
Che cosa sta cercando di fare il XmlSerializer
qui? Perché sta tentando di caricare un assembly già caricato? Cosa diavolo significa "Puntatore non valido"? E soprattutto, come dovrei fare il debug di qualcosa del genere?
Non so che errore specifico, ma si noti che XmlSerializer utilizza la generazione di codice e la compilazione dinamica, quindi sta tentando di creare un * nuovo * assembly che fa riferimento a quelli di cui ha bisogno. Sembra che questo nuovo assembly (generato) non sia soddisfatto del riferimento. Sono (per esempio) tutti i tipi necessari coinvolti 'pubblico'? –
È sicuramente un problema di riferimento. Apri ClientCustomFeatures.dll in reflector e cerca eventuali riferimenti che potresti non avere. –