Ich habe ein Problem mit der XML-Deserialisierung, das mich verblüfft.Warum verursacht XmlSerializer.Deserialize das Werfen einer System.IO.FileLoadException?
Ich erstelle eine Anwendung, die lokale Anpassung verschiedener Dienste unterstützt, die es verwendet. Ich habe eine abstrakte ServiceLocator
Klasse implementiert, deren Methoden verschiedene Objekte zurückgeben. Jede benutzerdefinierte Installation ist dafür verantwortlich, eine Unterklasse davon zu implementieren und Implementierungen dieser Methoden bereitzustellen. Das Fleisch dieser Klasse sieht wie folgt aus:
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();
}
Das funktioniert ganz gut: Ich erhalte den Pfad zum benutzerdefinierten Assembly aus der Anwendungskonfigurationsdatei verfügt, das Programm ruft Initialize
, und dann kann die Anwendung der verschiedenen Methoden aufrufen unter ServiceLocator.Default
und sie geben die entsprechenden benutzerdefinierten Implementierungen der Dienste zurück.
Einer dieser Dienste ist ein DefaultValuesContainer
. Dies ist ein einfaches Objekt, das Eigenschaften bereitstellt, deren Werte in einer Benutzereinstellungsdatei beibehalten werden müssen. Die Idee ist, dass ich dieses Objekt in eine einzige Benutzereinstellung vom Typ string
serialisieren kann. Es macht eine Benutzer-Einstellungsdatei, die Sie nicht manuell bearbeiten möchten, aber ich bin damit einverstanden.
Hier ist eine konkrete Umsetzung 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));
}
Hier ist das Ding.
Ich habe Komponententests dafür mit NUnit gebaut. Wenn ich die Tests in der Testvorrichtungsklasse ausfühle, die die benutzerdefinierten Funktionen des Clients ausübt, funktionieren sie. Wenn ich die gesamte Testsuite laufen, wirft die letzte Zeile des oben genannten Verfahrens diese Ausnahme:
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
ich als eine Art verwirrt, warum. Die Methode SetUp
wird weiterhin ausgeführt, und ServiceLocator.Default
gibt immer noch ein Objekt vom Typ ClientServiceLocator
zurück, was bedeutet, dass die Baugruppe ClientCustomFeatures
geladen wurde. Tatsächlich ist die Methode, die die Ausnahme auslöst, in der Assembly, die mir gesagt wurde, nicht geladen werden kann.
Was versucht die XmlSerializer
hier zu tun? Warum versucht es eine geladene Assembly zu laden? Was in aller Welt bedeutet "ungültiger Zeiger"? Und vor allem, wie sollte ich so etwas debuggen?
Ich kenne diesen spezifischen Fehler nicht, aber beachten Sie, dass XmlSerializer Code-Generierung und dynamische Kompilierung verwendet, so dass es versucht, eine * neue * Assembly zu erstellen, die auf die benötigt, die es benötigt. Es sieht so aus, als ob diese neue (generierte) Baugruppe nicht mit der Referenz zufrieden ist. Sind beispielsweise alle erforderlichen Arten "öffentlich"? –
Es ist sicher ein Referenzproblem. Öffnen Sie ClientCustomFeatures.dll im Reflector und suchen Sie nach Referenzen, die Sie möglicherweise nicht haben. –