XmlSerializer gibt FileNotFoundException im Konstruktor aus

347

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?

Irwin
quelle
5
OK, diese Frage ist nur meine C # -Version einer bereits gestellten VB-Frage: stackoverflow.com/questions/294659/… Danke Jungs.
Irwin
1
Sechs Jahre später ist die Antwort von @VladV die einfachste und am wenigsten nachteilige Lösung. Ändern Sie einfach das Generate serialization assemblyDropdown-Menü in "Ein" anstelle von "Auto".
Heliac
@Heliac: Ich bin anderer Meinung. Es funktioniert nicht immer. Bitte lesen Sie den Kommentar von Benoit Blanchon zu Vlads Antwort. Die einfachste Antwort für mich ist, String.Collection nicht in Konfigurationsdateien zu verwenden. Stattdessen verwende ich: string [] items = Settings.Default.StringofNewlineDelimitedItems.Split (new [] {Environment.NewLine});
Andrew Dennison

Antworten:

388

Ob Sie es glauben oder nicht, das ist normales Verhalten. Eine Ausnahme wird ausgelöst, aber vom XmlSerializer behandelt. Wenn Sie sie also einfach ignorieren, sollte alles in Ordnung bleiben.

Ich fand das sehr ärgerlich, und es gab viele Beschwerden darüber, wenn Sie ein bisschen suchen, aber nach dem, was ich gelesen habe, hat Microsoft nicht vor, etwas dagegen zu unternehmen.

Sie können vermeiden, dass beim Debuggen ständig Ausnahme-Popups angezeigt werden, wenn Sie Ausnahmen der ersten Chance für diese bestimmte Ausnahme deaktivieren. Gehen Sie in Visual Studio zu Debug -> Ausnahmen (oder drücken Sie Ctrl+ Alt+ E), Common Language Runtime Exceptions -> System.IO -> System.IO.FileNotFoundException .

Informationen dazu finden Sie in der C # XmlSerializer FileNotFound-Ausnahme (in der das Chris Xells -Tool XmlSerializerPreCompiler erläutert wird ).

Martin Sherburn
quelle
162
Eine Möglichkeit, dieses Problem zu beheben, besteht darin, die Option "Nur mein Code" unter Extras -> Optionen -> Debuggen -> Allgemeine Optionen zu aktivieren.
Frederic
26
@Frederic: Dieser Kommentar ist fantastisch! Ich sitze hier mit einem "WTF!?" Ausdruck auf meinem Gesicht, der versucht, diese falsche Ausnahme zu finden, und ich finde diese Frage mit Antwort (Es ist Microsofts Schuld, was ist noch neu?), aber ich wollte die Ausnahmebehandlung nicht deaktivieren, weil ich sie möglicherweise benötige mein Code. A +!
Kumba
27
Ich denke, Hans 'Vorschlag unten ist wertvoller - verwenden Sie einen anderen Methodenaufruf, der diese Ausnahme überhaupt nicht erzeugt: XmlSerializer serializer = XmlSerializer.FromTypes (new [] {typeof (MyType)}) [0];
hell
3
Das Problem ist, dass dies meinen Test nicht besteht, so dass ich die Ausnahme nicht einfach "ignorieren" kann
Csaba Toth
16
Es tut mir leid, aber das ist ein schrecklicher Vorschlag. FileNotFoundException ist meiner Erfahrung nach eine der häufigsten, und das Deaktivieren dieser Ausnahmeberichterstattung erfordert eines Tages nur noch Probleme. Aktivieren Sie besser "Just My Code" oder aktivieren Sie die Erstellung der unten beschriebenen Serialisierungsassemblys.
Quarkly
104

Wie Martin Sherburn sagte, ist dies normales Verhalten. Der Konstruktor des XmlSerializer versucht zunächst, eine Assembly mit dem Namen [YourAssembly] .XmlSerializers.dll zu finden, die die generierte Klasse für die Serialisierung Ihres Typs enthalten soll. Da eine solche DLL noch nicht generiert wurde (standardmäßig nicht), wird eine FileNotFoundException ausgelöst. In diesem Fall fängt der XmlSerializer-Konstruktor diese Ausnahme ab und die DLL wird zur Laufzeit automatisch vom XmlSerializer-Konstruktor generiert (dies erfolgt durch Generieren von C # -Quelldateien im Verzeichnis% temp% Ihres Computers und anschließendes Kompilieren mit dem C # -Compiler). Zusätzliche Konstruktionen eines XmlSerializers für denselben Typ verwenden nur die bereits generierte DLL.

UPDATE: Ab .NET 4.5 wird XmlSerializerweder eine Codegenerierung noch eine Kompilierung mit dem C # -Compiler durchgeführt, um zur Laufzeit eine Serializer-Assembly zu erstellen, es sei denn, dies wird ausdrücklich durch Festlegen einer Konfigurationsdateieinstellung ( useLegacySerializerGeneration ) erzwungen . Diese Änderung beseitigt die Abhängigkeit von csc.exeund verbessert die Startleistung. Quelle: .NET Framework 4.5 Readme , Abschnitt 1.3.8.1.

Die Ausnahme wird vom XmlSerializer-Konstruktor behandelt. Sie müssen nichts selbst tun. Klicken Sie einfach auf "Weiter" (F5), um die Ausführung Ihres Programms fortzusetzen, und alles wird in Ordnung sein. Wenn Sie von den Ausnahmen gestört werden, die die Ausführung Ihres Programms stoppen und einen Ausnahmehelfer öffnen, haben Sie entweder "Nur mein Code" deaktiviert oder die FileNotFoundException so eingestellt, dass die Ausführung beim Auslösen unterbrochen wird, anstatt bei "Benutzer-". unbehandelt '.

Um 'Nur mein Code' zu aktivieren, gehen Sie zu Extras >> Optionen >> Debuggen >> Allgemein >> Nur meinen Code aktivieren. Um die Unterbrechung der Ausführung zu deaktivieren, wenn FileNotFound ausgelöst wird, gehen Sie zu Debug >> Ausnahmen >> Suchen >> Geben Sie 'FileNotFoundException' ein >> deaktivieren Sie das Kontrollkästchen 'Ausgeworfen' in System.IO.FileNotFoundException.

Allon Guralnek
quelle
+1 für das Update: Dies erklärt das unterschiedliche Verhalten beim Debuggen von Testfällen
mbx
3
Ihr Update schlägt vor, dass diese Ausnahme in .NET 4.5 nicht auftreten sollte, aber ich sehe sie immer noch.
Timbo
@ Timbo: Ich verstehe nicht, warum Sie diese Ausnahme mit .NET 4.5 nicht bekommen würden. Es wird immer noch nach einer Datei gesucht, und wenn die Datei fehlt, FileNotFoundExceptionwird eine ausgelöst. Der Unterschied besteht nicht darin, wie die Existenz der Assembly überprüft wird, sondern darin, wie sie generiert wird, sobald festgestellt wird, dass sie fehlt. Zuvor wurde die C # -Code-Textgenerierung mit einem Aufruf des C # -Compilers verwendet, um die IL zu erstellen. Ab .NET 4.5 wird IL ohne Verwendung eines Compilers direkt ausgegeben.
Allon Guralnek
1
Ich wünschte nur, MS würde dies so implementieren, als ob (File.Exists (...)) {Load} else {Fallback} anstelle von {Load} catch {Fallback}. Eine ausnahmebasierte Flusskontrolle riecht schlecht und macht meine Debugging-Erfahrung schwieriger und spröder als nötig.
Timbo
1
@ Timbo: Eine einfache File.Exists()kann nicht ausreichen. Das Auffinden einer Assembly ist keine einfache Angelegenheit. Die Laufzeit wird an mehreren Stellen angezeigt, und ich glaube, dass sich das Verhalten je nach Umgebung ändert (Konsolenanwendung vs. Hosting in IIS usw.). Ich denke, was hätte implementiert werden sollen, war ein TryLoadAssembly()oder ähnliches.
Allon Guralnek
63

In den Visual Studio-Projekteigenschaften (Seite "Erstellen", wenn ich mich richtig erinnere) gibt es eine Option mit der Bezeichnung "Serialisierungsassembly generieren". Versuchen Sie, es für ein Projekt zu aktivieren , das [mit Assembly of MyType] generiert .

VladV
quelle
4
Siehe auch stackoverflow.com/a/8798289/1164966, wenn die Serialisierungsassembly noch nicht von Visual Studio generiert wurde.
Benoit Blanchon
Beste, klarste, prägnanteste Antwort! Ich wünschte, ich könnte auch wieder abstimmen!
John Zabroski
59

Dafür gibt es eine Problemumgehung. Wenn du benutzt

XmlSerializer lizer = XmlSerializer.FromTypes(new[] { typeof(MyType) })[0];

es sollte diese Ausnahme vermeiden. Das hat bei mir funktioniert.

WARNUNG: Nicht mehrmals verwenden, da sonst ein Speicherverlust auftritt

Sie werden Speicher wie verrückt verlieren, wenn Sie diese Methode verwenden, um Instanzen XmlSerializerfür denselben Typ mehr als einmal zu erstellen !

Dies liegt daran, dass diese Methode das integrierte Caching umgeht, sofern die Konstruktoren XmlSerializer(type)und vorhanden sind XmlSerializer(type, defaultNameSpace)(alle anderen Konstruktoren umgehen auch den Cache).

Wenn Sie eine Methode verwenden, um einen XmlSerializer zu erstellen, der nicht über diese beiden Konstruktoren erfolgt, müssen Sie Ihr eigenes Caching implementieren, da sonst der Speicher blutet.

Quadfinität
quelle
44
WARNUNG: Sie werden Speicher wie verrückt verlieren, wenn Sie diese Methode verwenden, um Instanzen XmlSerializerfür denselben Typ mehr als einmal zu erstellen ! Dies liegt daran, dass diese Methode das integrierte Caching umgeht, sofern die Konstruktoren XmlSerializer(type)und vorhanden sind XmlSerializer(type, defaultNameSpace)(alle anderen Konstruktoren umgehen auch den Cache). Wenn Sie eine Methode verwenden, um eine zu erstellen XmlSerializer, die nicht über diese beiden Konstruktoren erfolgt, müssen Sie Ihr eigenes Caching implementieren, da sonst das Blutungsgedächtnis beeinträchtigt wird.
Allon Guralnek
4
@AllonGuralnek Nun, ich werde verdammt sein ... du bist absolut korrekt; Ein weiteres Eingraben über Reflector zeigt, dass der Cache zwar überprüft wird, dies jedoch nach dem Generieren der Serialisierungsbaugruppe! Wtf?!?
JerKimball
4
Es stellt sich heraus, dass es ein bekannter Fehler ist: weblogs.asp.net/cschittko/archive/2005/01/14/353435.aspx
JerKimball
3
@ JerKimball: Diese Seite lügt eigentlich nicht. Wie Sie festgestellt haben, FromTypesscheint der Cache gefüllt zu sein. Es sollte also eine gültige Methode sein, einen leeren XmlSerializerCache in einer Anweisung aufzuwärmen (wie im Artikel vorgeschlagen), aber eine wirklich schlechte Methode, um etwas daraus abzurufen (sollte nur über die einfachsten Konstruktoren erfolgen). Auf jeden Fall wusste ich nicht, dass es sich um einen Fehler handelt. Ich dachte immer, dass alles, was undicht ist, auslaufen soll (wie die fortgeschritteneren XmlSerializerKonstruktoren). Ich hätte nicht einmal darüber nachgedacht, es zu verwenden, FromTypes()da Sie es einfach tun können types.Select(t => new XmlSerializer(t)).
Allon Guralnek
2
@AllonGuralnek Der nicht prüfende Aspekt der Verwendung FromTypeshat seinen Reiz - obwohl die ausgelösten Ausnahmen alle abgefangen werden, ist es eine kostspielige Operation; Der Ansatz "Cache your own way" scheint die einzige Problemumgehung zu sein, da der einzige offiziell unterstützte Fix in einer obskuren webbasierten Assembly zu liegen scheint. (Bearbeiten:
Ehrlich
22

Ich bin genau auf dieses Problem gestoßen und konnte es mit keiner der genannten Lösungen umgehen.

Dann habe ich endlich eine Lösung gefunden. Es scheint, dass der Serializer nicht nur den Typ, sondern auch die verschachtelten Typen benötigt. Ändern Sie dies:

XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));

Dazu:

XmlSerializer xmlSerializer = new XmlSerializer(typeof(T).GetNestedTypes());

Das Problem wurde für mich behoben. Keine Ausnahmen mehr oder so.

Eisig
quelle
8
Das hat bei mir funktioniert. Mit .Net4.0 ist das Formatvar xmlSerializer = new XmlSerializer(typeof(T), typeof(T).GetNestedTypes());
user3161729
1
Das hat auch bei mir funktioniert. Es scheint jedoch nur beim Serialisieren notwendig zu sein, nicht beim Deserialisieren. Vielleicht macht das Sinn, vielleicht auch nicht.
SteveCinq
2
Dies führt auch zu einem Speicherverlust, wenn es häufig ausgeführt wird.
Volodymyr Kotylo
9

Meine Lösung besteht darin, direkt zur Reflexion überzugehen, um den Serializer zu erstellen. Dies umgeht das seltsame Laden von Dateien, das die Ausnahme verursacht. Ich habe dies in eine Hilfsfunktion gepackt, die sich auch um das Zwischenspeichern des Serializers kümmert.

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;
    }
}
d - b
quelle
2 Probleme hier - erstens ist Ihr Code nicht threadsicher und zweitens (was noch wichtiger ist) versuchen Sie zu replizieren, was die .net-Laufzeit bereits tut (basierend auf dem von Ihnen verwendeten ctor). dh es gibt keine Notwendigkeit für diesen Code
Dave Black
@ DaveBlack: Ja, Quadfinitys Antwort mit Caching zu einem ConcurrentDictionary wäre besser
d - b
@db Mein zweiter Punkt war, dass Caching nicht einmal benötigt wird - solange Sie einen der 2 Ctors verwenden, die das Framework zwischenspeichert (OP verwendet den ersten). Von MSDN: Um die Leistung zu steigern, generiert die XML-Serialisierungsinfrastruktur dynamisch Assemblys, um bestimmte Typen zu serialisieren und zu deserialisieren. Das Framework findet diese Assemblys und verwendet sie erneut. Dieses Verhalten tritt nur auf, wenn die folgenden ctors verwendet werden: XmlSerializer.XmlSerializer (Typ) XmlSerializer.XmlSerializer (Typ, Zeichenfolge
Dave Black
@ DaveBlack: Ja, aber diese Konstruktoren lösen intern eine Ausnahme aus und fangen sie ab, selbst wenn die Verwendung vollständig gültig ist. Das ist schlecht, und das ist der Grund, warum das OP die Frage überhaupt gestellt hat.
d - b
@db Stimmt, aber was ich sagen wollte (aber nicht klar war - ich entschuldige mich) war, dass die einzigen Zeilen Ihrer Lösung, die notwendig sind, die ersten 3 Zeilen im else-Zustand sind.
Dave Black
8

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 Zugriff)
  2. Generieren Sie die Serialisierungsdatei mit sgen.exe

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

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

}

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

'sgen.exe MyAssembly.dll' generiert die Datei MyAssembly.XmlSerializers.dll

Diese beiden Änderungen bewirken, dass das .net die Assembly direkt findet. Ich habe es überprüft und es funktioniert unter .NET Framework 3.5 mit Visual Studio 2008

Ami Bar
quelle
Ok, und ist es ohne diese Änderungen gescheitert, und wenn ja, warum?
John Saunders
1
Ich kann keinen Grund finden, warum mein Projekt 4.0 in VS2012 plötzlich fehlschlug. Das "Ignorieren" des Fehlers war keine Option, da er jedes Mal auftrat, wenn ich versuchte, auf Active Directory zuzugreifen. Ignorieren würde also bedeuten, sich nicht zu authentifizieren. Ich bin immer noch sehr frustriert, dass VS2012 die Serialisierungs-DLL nicht ordnungsgemäß automatisch generiert. Diese Schritte lieferten jedoch die perfekte Lösung.
Sfuqua
6

Diese Ausnahme kann auch von einem verwalteten Debugging-Assistenten (MDA) namens BindingFailure abgefangen werden.

Dieser MDA ist nützlich, wenn Ihre Anwendung für die Auslieferung von vorgefertigten Serialisierungsbaugruppen ausgelegt ist. Wir tun dies, um die Leistung unserer Anwendung zu steigern. Auf diese Weise können wir sicherstellen, dass die vorgefertigten Serialisierungsassemblys von unserem Erstellungsprozess ordnungsgemäß erstellt und von der Anwendung geladen werden, ohne dass sie im laufenden Betrieb neu erstellt werden müssen.

Es ist wirklich nicht nützlich, außer in diesem Szenario, da, wie andere Poster gesagt haben, die Serialisierungsassembly zur Laufzeit neu erstellt wird, wenn ein Bindungsfehler vom Serializer-Konstruktor abgefangen wird. So können Sie es normalerweise ausschalten.

HiredMind
quelle
6

Die Funktion XmlSerializer.FromTypes löst die Ausnahme nicht aus, verliert jedoch den Speicher. Aus diesem Grund müssen Sie einen solchen Serializer für jeden Typ zwischenspeichern, um Speicherverluste bei jeder erstellten Instanz zu vermeiden.

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

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

Die Fabrik sieht aus wie:

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 Speicherverlusts (bitte überprüfen Sie den Code):

    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;
    }       
}
Tomas Kubes
quelle
Sie sollten stattdessen ConcurrentDictionary verwenden. Dieser Code kann blockieren.
Behrooz
Wie kann es zu einem Deadlock kommen, wenn sich die gesamte Verwaltung mit Wörterbuch im Sperrbereich befindet?
Tomas Kubes
Entschuldigung, ich habe die Worte verwirrt. Was ich damit gemeint habe ist, dass es einen Gegenstand mehr als einmal einfügen kann. weil es eine Lücke zwischen dem Zeitpunkt der Überprüfung auf Existenz und dem Zeitpunkt der Einfügung gibt. Das gleichzeitige Wörterbuch verwendet eine Art Zwei-Phasen-Verriegelung (Tasche [0] und dann Tasche [Hash]]) und enthält einen Verweis auf die Tasche, die den Gegenstand einfügen / enthalten muss, an dem Sie arbeiten. Es ist schneller, sicherer und sauberer.
Behrooz
Ja und nein. Sie haben Recht, dass es vorkommen kann, dass gleichzeitig ein Serializer desselben Typs auf zwei Threads parallel erstellt und dann zweimal zum Wörterbuch hinzugefügt wird. In diesem Fall ersetzt der zweite Einsatz nur den ersten, aber der Verriegelungsabschnitt garantiert die Gewindesicherheit und der allgemeine Nachteil ist ein kleiner Speicherverlust. Dies ist eine Leistungsoptimierung, da Thread 1 mit Serializer vom Typ A im realen Szenario nicht durch Thread 2 mit Serializer vom Typ B blockiert werden soll.
Tomas Kubes
Ich kann mir vorstellen, dass die Lösung noch besser (ohne theoretischen Speicherverlust), aber komplizierter ist.
Tomas Kubes
3

Die Fehlerbehebung bei Kompilierungsfehlern ist dagegen sehr kompliziert. Diese Probleme manifestieren 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 eine nicht gefundene Dateiausnahme 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 enthält einige gute Informationen, um diesen Verdacht zu unterstützen. Die Ausnahme trat auf, als der XmlSerializer versuchte, eine von CodeDOM generierte Assembly zu laden, die die System.Reflection.Assembly.Load-Methode aufruft. Die Ausnahme liefert keine Erklärung dafür, warum die Assembly, die der XmlSerializer erstellen sollte, nicht vorhanden war. Im Allgemeinen ist die Assembly nicht vorhanden, da die Kompilierung fehlgeschlagen ist. Dies kann vorkommen, weil die Serialisierungsattribute in seltenen Fällen 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 temporäre Verzeichnis zugreifen kann.

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

Zyphrax
quelle
er hat nicht angegeben, dass dies zur Laufzeit geschah. Eine andere Sache, an die ich denken kann, ist, dass Sie möglicherweise einen Namespace / Klassenkonflikt haben. Wie lautet der vollständige Name Ihres MyType?
Zyphrax
Ja, ich habe deinen Link überprüft. Die Informationen zu den Konstruktoren waren zwar hilfreich, aber nicht das, was ich brauchte.
Irwin
5
@SpaceghostAl Sie können zur Laufzeit kompilieren. Und genau das macht XmlSerializer. Zur Laufzeit wird dynamisch eine Assembly erstellt, die XML für den jeweiligen Typ (de) serialisiert. Aus irgendeinem Grund schlägt dieser Prozess für das OP fehl. Möglicherweise aufgrund von Berechtigungsproblemen, z. B. in einem temporären Verzeichnis. (Könnte sogar so albern sein wie kein Speicherplatz mehr.)
Nr.
Bist du dir da sicher? Ich war mir ziemlich sicher, dass das Serialisierungsmaterial während des Builds in eine Assembly mit dem Namen YourAssemblyName.XmlSerializers.dll kompiliert wird und nicht zur Laufzeit kompiliert wird. Dies kann aus allen möglichen Gründen fehlschlagen, am wenigsten aus allen NTFS-Berechtigungen im Bereitstellungsordner.
Tomfanning
1
Ich wünschte, ich könnte dies mehrmals positiv bewerten. Ihr Hinweis, dass das Konto nicht auf den temporären Ordner zugreifen kann, hat die Antwort für mich ausgelöst. Nachdem ich mein Dienstkonto zur Administratorgruppe auf dem Server hinzugefügt hatte, funktionierte es einfach. Vielen Dank!
Bob Horn
2

In den Projekteigenschaften von Visual Studio gibt es die Option "Serialisierungsassembly generieren". Versuchen Sie, es für ein Projekt zu aktivieren, das [mit Assembly of MyType] generiert.

Pascal
quelle
1

Eine benutzerdefinierte Klasse zum Serialisieren:

[Serializable]
public class TestClass
{
    int x = 2;
    int y = 4;
    public TestClass(){}
    public TestClass(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    public int TestFunction()
    {
        return x + y;
    }
}

Ich habe das Code-Snippet angehängt. Vielleicht kann dir das helfen.

static void Main(string[] args)
{
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(TestClass));

    MemoryStream memoryStream = new MemoryStream();
    XmlTextWriter xmlWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);

    TestClass domain = new TestClass(10, 3);
    xmlSerializer.Serialize(xmlWriter, domain);
    memoryStream = (MemoryStream)xmlWriter.BaseStream;
    string xmlSerializedString = ConvertByteArray2Str(memoryStream.ToArray());

    TestClass xmlDomain = (TestClass)DeserializeObject(xmlSerializedString);

    Console.WriteLine(xmlDomain.TestFunction().ToString());
    Console.ReadLine();
}
shahjapan
quelle
2
-1 für die Nichtverwendung von Blöcken zur Verhinderung von Ressourcenlecks und für die Verwendung von XmlTextWriter.
John Saunders
ok stimme zu, aber ich habe immer noch XmlSerializer verwendet xmlSerializer = neuer XmlSerializer (typeof (TestClass)); aber ich bekomme die besagte Ausnahme nicht.
Shahjapan
1

Ich hatte ein ähnliches Problem und das Ignorieren der Ausnahme funktionierte bei mir nicht. Mein Code hat die Konfiguration von NServiceBus aufgerufenConfigure.With(...).XmlSerializer()...

Was es für mich behoben hat, war, die Plattform für mein Projekt zu ändern.

  1. Gehen Sie zu Build \ Configuration Manager ...
  2. Finden Sie Ihr Projekt und ändern Sie die Plattform (in meinem Fall von x86 auf eine beliebige CPU)
kkelley
quelle
1

Nur als Referenz. Ausgehend von den Antworten und Kommentaren der DB kam ich mit dieser Lösung, die der DB-Lösung nahe kommt. Es funktioniert in allen meinen Fällen gut und ist threadsicher. Ich denke nicht, dass die Verwendung eines ConcurrentDictionary in Ordnung gewesen wäre.

using System;
using System.Collections.Generic;
using System.Xml.Serialization;

namespace HQ.Util.General
{
    public class XmlSerializerHelper
    {
        private static readonly Dictionary<Type, XmlSerializer> _dictTypeToSerializer = new Dictionary<Type, XmlSerializer>();

        public static XmlSerializer GetSerializer(Type type)
        {
            lock (_dictTypeToSerializer)
            {
                XmlSerializer serializer;
                if (! _dictTypeToSerializer.TryGetValue(type, out serializer))
                {
                    var importer = new XmlReflectionImporter();
                    var mapping = importer.ImportTypeMapping(type, null, null);
                    serializer = new XmlSerializer(mapping);
                    return _dictTypeToSerializer[type] = serializer;
                }

                return serializer;
            }
        }
    }
}

Verwendungszweck:

        if (File.Exists(Path))
        {
            using (XmlTextReader reader = new XmlTextReader(Path))
            {
                // XmlSerializer x  = new XmlSerializer(typeof(T));
                var x = XmlSerializerHelper.GetSerializer(typeof(T));

                try
                {
                    options = (OptionsBase<T>)x.Deserialize(reader);
                }
                catch (Exception ex)
                {
                    Log.Instance.AddEntry(LogType.LogException, "Unable to open Options file: " + Path, ex);
                }
            }
        }
Eric Ouellet
quelle
0

Ihr Typ verweist möglicherweise auf andere Assemblys, die weder im GAC noch in Ihrem lokalen bin-Ordner gefunden werden können ==> ...

"oder eine seiner Abhängigkeiten. Das System kann die angegebene Datei nicht finden."

Können Sie ein Beispiel für den Typ geben, den Sie serialisieren möchten?

Hinweis: Stellen Sie sicher, dass Ihr Typ Serializable implementiert.

Henrik
quelle
0

Ich habe den gleichen Fehler erhalten, und dies lag an dem Typ, den ich deserialisieren wollte, ohne einen standardmäßigen parameterlosen Konstruktor . Ich habe einen Konstruktor hinzugefügt und er hat funktioniert.

Kay One
quelle
0

Ich hatte das gleiche Problem, bis ich ein Drittanbieter-Tool zum Generieren der Klasse aus der XSD verwendete und es funktionierte! Ich stellte fest, dass das Tool oben in meiner Klasse zusätzlichen Code hinzufügte. Als ich denselben Code oben in meiner ursprünglichen Klasse hinzufügte, funktionierte er. Folgendes habe ich hinzugefügt ...

#pragma warning disable
namespace MyNamespace
{
  using System;
  using System.Diagnostics;
  using System.Xml.Serialization;
  using System.Collections;
  using System.Xml.Schema;
  using System.ComponentModel;
  using System.Xml;
  using System.Collections.Generic;

  [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.6.1064.2")]
  [System.SerializableAttribute()]
  [System.Diagnostics.DebuggerStepThroughAttribute()]
  [System.ComponentModel.DesignerCategoryAttribute("code")]
  [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
  [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
  public partial class MyClassName
  {
  ...
TheJonz
quelle
0

ConcurrentDictionaryIch habe viele Empfehlungen für die Verwendung von a gesehen , aber keine soliden Beispiele dafür. Deshalb werde ich meinen Hut in dieses Lösungsrennen werfen. Ich bin kein thread-sicherer Entwickler. Wenn dieser Code nicht solide ist, melden Sie sich bitte für diejenigen, die danach folgen.

public static class XmlSerializerHelper
{
    private static readonly ConcurrentDictionary<Type, XmlSerializer> TypeSerializers = new ConcurrentDictionary<Type, XmlSerializer>();

    public static XmlSerializer GetSerializer(Type type)
    {
        return TypeSerializers.GetOrAdd(type,
        t =>
        {
            var importer = new XmlReflectionImporter();
            var mapping = importer.ImportTypeMapping(t, null, null);
            return new XmlSerializer(mapping);
        });
    }
}

Ich habe andere Beiträge gesehen, die den Wert betreffen ConcurrentDictionaryund Lazyladen. Ich bin mir nicht sicher, ob das hier relevant ist oder nicht, aber hier ist der Code dafür:

private static readonly ConcurrentDictionary<Type, Lazy<XmlSerializer>> TypeSerializers = new ConcurrentDictionary<Type, Lazy<XmlSerializer>>();

public static XmlSerializer GetSerializer(Type type)
{
    return TypeSerializers.GetOrAdd(type,
    t =>
    {
        var importer = new XmlReflectionImporter();
        var mapping = importer.ImportTypeMapping(t, null, null);
        var lazyResult = new Lazy<XmlSerializer>(() => new XmlSerializer(mapping), LazyThreadSafetyMode.ExecutionAndPublication);
        return lazyResult;
    }).Value;
}
Airn5475
quelle