2010-09-26 8 views
6

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?

+2

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"? –

+3

Es ist sicher ein Referenzproblem. Öffnen Sie ClientCustomFeatures.dll im Reflector und suchen Sie nach Referenzen, die Sie möglicherweise nicht haben. –

Antwort

0

Ich hatte Probleme mit dem Assembly Loader (Fusion?), Wenn eine Assembly eine andere Assembly lädt, die selbst (nicht GAC) Referenzen hat. YourDLL.XmlSerializers.dll könnte eine solche Baugruppe sein. Versuchen Sie, die Visual Studio-Option zum automatischen Generieren einer XML-Serialisierungsassemblierung (Projektoptionen) zu deaktivieren. Dadurch wird die zusätzliche Assembly (und damit die Abhängigkeit davon) entfernt.

0

Fusion Log Viewer

helfen Um die Montage Laden Probleme wie diese zu diagnostizieren, werfen Sie einen Blick auf die Fusion Log Viewer (AKA Fuslogvw.exe).

Fusion == Die .NET-Komponente, die Baugruppen findet und lädt.

0

Versuchen Sie, die Linie zu ersetzen:

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

mit:

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

Wenn die benutzerdefinierte Assembly nicht weiß, wo die Baugruppe laden Sie die ClientCustomFeatures Klasse enthält, dies geschehen wird. Dies tritt auf, wenn Sie Ihre benutzerdefinierte Assembly an einem Speicherort bereitgestellt haben, der sich nicht im Pfad der Hauptbaugruppe befindet und sich Ihre Hauptbaugruppe nicht im gac befindet. Wenn also Ihre benutzerdefinierten Assemblies aus Unterverzeichnissen Ihrer Hauptbaugruppe geladen werden, sollte dies wegfallen. Wenn sie sich jedoch an beliebigen Orten befinden, liegt ein Problem vor, da sie Ihre Hauptbaugruppe laden müssen, da sie Zugriff auf den ClientCustomFeatures-Typ benötigen.

+0

Nun, alle Assemblies befinden sich im selben Verzeichnis, also glaube ich nicht, dass das der Fall ist. –

+1

Hallo Robert, werfen Sie einen Blick auf diese Website: http://msdn.microsoft.com/en-us/library/aa302290.aspx Es hat eine Reihe von hervorragenden Tipps zur Fehlerbehebung, die auf das Problem beziehen, die Sie bekommen und Gründe warum es könnte vorkommen. Es gibt auch einen Link zu einem Tool, das Ihnen bei der Fehlerbehebung helfen soll. Da wir nicht auf all Ihren Code zugreifen können, können wir dies nicht für Sie tun, aber ich würde sehr interessant sein zu wissen, was das Ergebnis dieses kleinen Abenteuers ist :) Sie werden sich die "Ausnahmen im Konstruktor ansehen" wollen "Abschnitt – Kell

+0

Nur an etwas gedacht: NUnit wird in einem temporären Cache-Speicherort ausgeführt und verfügt möglicherweise nicht über die entsprechenden Berechtigungen, um alle Assemblys zu laden und Klassen zu generieren. Aber lesen Sie die obige URL, es hat viel mehr Routen der Untersuchung oder Sie. – Kell

Verwandte Themen