409 Stimmen

XmlSerializer gibt FileNotFoundException beim Konstruktor

Eine Anwendung, mit der ich gearbeitet habe, schlägt fehl, wenn ich versuche, Typen zu serialisieren.

Eine Aussage wie

XmlSerializer lizer = new XmlSerializer(typeof(MyType));

produziert:

System.IO.FileNotFoundException occurred
  Message="Could not load file or assembly '[Containing Assembly of MyType].XmlSerializers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified."
  Source="mscorlib"
  FileName="[Containing Assembly of MyType].XmlSerializers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
  FusionLog=""
  StackTrace:
       at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
       at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)

Ich definiere keine speziellen Serialisierer für meine Klasse.

Wie kann ich dieses Problem beheben?

9voto

edeboursetty Punkte 5504

Meine Lösung ist es, direkt zu Reflection zu gehen, um den Serializer zu erstellen. Dadurch wird das seltsame Laden der Datei umgangen, das die Ausnahme verursacht. Ich verpackte dies in einer Hilfsfunktion, die auch kümmert sich um die Zwischenspeicherung der Serializer.

private static readonly Dictionary<Type,XmlSerializer> _xmlSerializerCache = new Dictionary<Type, XmlSerializer>();

public static XmlSerializer CreateDefaultXmlSerializer(Type type) 
{
    XmlSerializer serializer;
    if (_xmlSerializerCache.TryGetValue(type, out serializer))
    {
        return serializer;
    }
    else
    {
        var importer = new XmlReflectionImporter();
        var mapping = importer.ImportTypeMapping(type, null, null);
        serializer = new XmlSerializer(mapping);
        return _xmlSerializerCache[type] = serializer;
    }
}

8voto

Ami Bar Punkte 81

Um die Ausnahme zu vermeiden, müssen Sie zwei Dinge tun:

  1. Fügen Sie der serialisierten Klasse ein Attribut hinzu (ich hoffe, Sie haben Zugang)
  2. Erzeugen Sie die Serialisierungsdatei mit sgen.exe

Fügen Sie das Attribut System.Xml.Serialization.XmlSerializerAssembly zu Ihrer Klasse hinzu. Ersetzen Sie "MyAssembly" durch den Namen der Assembly, in der sich MyClass befindet.

[Serializable]
[XmlSerializerAssembly("MyAssembly.XmlSerializers")]
public class MyClass
{
…
}

Erzeugen Sie die Serialisierungsdatei mit dem Dienstprogramm sgen.exe und stellen Sie sie mit der Assembly der Klasse bereit.

sgen.exe MyAssembly.dll' wird die Datei MyAssembly.XmlSerializers.dll erzeugen

Diese beiden Änderungen führen dazu, dass das .net die Baugruppe direkt findet. Ich habe es überprüft und es funktioniert auf .NET Framework 3.5 mit Visual Studio 2008

7voto

Tomas Kubes Punkte 21732

Funktion XmlSerializer.FromTypes wirft nicht die Ausnahme, aber es leckt den Speicher. Deshalb müssen Sie einen solchen Serializer für jeden Typ zwischenspeichern, um Speicherlecks für jede erstellte Instanz zu vermeiden.

Erstellen Sie Ihre eigene XmlSerializer-Fabrik und verwenden Sie sie einfach:

XmlSerializer serializer = XmlSerializerFactoryNoThrow.Create(typeof(MyType));

Die Fabrik sieht so aus:

public static class XmlSerializerFactoryNoThrow
{
    public static Dictionary<Type, XmlSerializer> _cache = new Dictionary<Type, XmlSerializer>();

    private static object SyncRootCache = new object();        

    /// <summary>
    /// //the constructor XmlSerializer.FromTypes does not throw exception, but it is said that it causes memory leaks
    /// http://stackoverflow.com/questions/1127431/xmlserializer-giving-filenotfoundexception-at-constructor
    /// That is why I use dictionary to cache the serializers my self.
    /// </summary>
    public static XmlSerializer Create(Type type)
    {
        XmlSerializer serializer;

        lock (SyncRootCache)
        {
            if (_cache.TryGetValue(type, out serializer))
                return serializer;
        }

        lock (type) //multiple variable of type of one type is same instance
        {
            //constructor XmlSerializer.FromTypes does not throw the first chance exception           
            serializer = XmlSerializer.FromTypes(new[] { type })[0];
            //serializer = XmlSerializerFactoryNoThrow.Create(type);
        }

        lock (SyncRootCache)
        {
            _cache[type] = serializer;
        }
        return serializer;
    }       
}

Kompliziertere Version ohne die Möglichkeit eines Speicherlecks (bitte jemand den Code überprüfen):

    public static XmlSerializer Create(Type type)
    {
        XmlSerializer serializer;

        lock (SyncRootCache)
        {
            if (_cache.TryGetValue(type, out serializer))
                return serializer;
        }

        lock (type) //multiple variable of type of one type is same instance
        {
            lock (SyncRootCache)
            {
                if (_cache.TryGetValue(type, out serializer))
                    return serializer;
            }
            serializer = XmlSerializer.FromTypes(new[] { type })[0];
            lock (SyncRootCache)
            {
                _cache[type] = serializer;
            }
        }          
        return serializer;
    }       
}

6voto

HiredMind Punkte 1746

Diese Ausnahme kann auch durch eine verwalteter Debugging-Assistent (MDA) namens BindingFailure.

Diese MDA ist nützlich, wenn Ihre Anwendung für die Auslieferung mit vorgefertigten Serialisierungsbaugruppen konzipiert ist. Wir tun dies, um die Leistung unserer Anwendung zu erhöhen. So können wir sicherstellen, dass die vorgefertigten Serialisierungsbaugruppen von unserem Build-Prozess ordnungsgemäß erstellt und von der Anwendung geladen werden, ohne dass sie im laufenden Betrieb neu erstellt werden.

Es ist wirklich nicht nützlich, außer in diesem Szenario, denn wie andere Poster gesagt haben, wenn ein Bindungsfehler durch den Serializer-Konstruktor gefangen wird, wird die Serialisierung Assembly zur Laufzeit neu erstellt. Sie können es also in der Regel ausschalten.

3voto

Zyphrax Punkte 17659

Die Fehlersuche bei Kompilierungsfehlern ist dagegen sehr kompliziert. Diese Probleme äußern sich in einer FileNotFoundException mit der Meldung:

File or assembly name abcdef.dll, or one of its dependencies, was not found. File name: "abcdef.dll"
   at System.Reflection.Assembly.nLoad( ... )
   at System.Reflection.Assembly.InternalLoad( ... )
   at System.Reflection.Assembly.Load(...)
   at System.CodeDom.Compiler.CompilerResults.get_CompiledAssembly() 

Sie fragen sich vielleicht, was die Ausnahme "Datei nicht gefunden" mit der Instanziierung eines Serializer-Objekts zu tun hat, aber denken Sie daran: Der Konstruktor schreibt C#-Dateien und versucht, sie zu kompilieren. Der Aufrufstapel dieser Ausnahme liefert einige gute Informationen, um diese Vermutung zu untermauern. Die Ausnahme trat auf, als der XmlSerializer versuchte, eine von CodeDOM generierte Assembly zu laden, indem er die Methode System.Reflection.Assembly.Load aufrief. Die Ausnahme bietet keine Erklärung dafür, warum die Assembly, die der XmlSerializer erstellen sollte, nicht vorhanden war. Im Allgemeinen ist die Assembly nicht vorhanden, weil die Kompilierung fehlgeschlagen ist, was passieren kann, weil die Serialisierungsattribute unter seltenen Umständen Code erzeugen, den der C#-Compiler nicht kompilieren kann.

Hinweis Dieser Fehler tritt auch auf, wenn der XmlSerializer unter einem Konto oder einer Sicherheitsumgebung ausgeführt wird, die nicht auf das temp-Verzeichnis zugreifen kann.

Quelle : http://msdn.microsoft.com/en-us/library/aa302290.aspx

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X