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?
c#
xml-serialization
Irwin
quelle
quelle
Generate serialization assembly
Dropdown-Menü in "Ein" anstelle von "Auto".Antworten:
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 ).
quelle
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.
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.
quelle
FileNotFoundException
wird 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.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 einTryLoadAssembly()
oder ähnliches.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 .
quelle
Dafür gibt es eine Problemumgehung. Wenn du benutzt
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
XmlSerializer
fü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 sindXmlSerializer(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.
quelle
XmlSerializer
für denselben Typ mehr als einmal zu erstellen ! Dies liegt daran, dass diese Methode das integrierte Caching umgeht, sofern die KonstruktorenXmlSerializer(type)
und vorhanden sindXmlSerializer(type, defaultNameSpace)
(alle anderen Konstruktoren umgehen auch den Cache). Wenn Sie eine Methode verwenden, um eine zu erstellenXmlSerializer
, die nicht über diese beiden Konstruktoren erfolgt, müssen Sie Ihr eigenes Caching implementieren, da sonst das Blutungsgedächtnis beeinträchtigt wird.FromTypes
scheint der Cache gefüllt zu sein. Es sollte also eine gültige Methode sein, einen leerenXmlSerializer
Cache 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 fortgeschrittenerenXmlSerializer
Konstruktoren). Ich hätte nicht einmal darüber nachgedacht, es zu verwenden,FromTypes()
da Sie es einfach tun könnentypes.Select(t => new XmlSerializer(t))
.FromTypes
hat 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: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:
Dazu:
Das Problem wurde für mich behoben. Keine Ausnahmen mehr oder so.
quelle
var xmlSerializer = new XmlSerializer(typeof(T), typeof(T).GetNestedTypes());
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.
quelle
Um die Ausnahme zu vermeiden, müssen Sie zwei Dinge tun:
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.
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
quelle
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.
quelle
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:
Die Fabrik sieht aus wie:
Kompliziertere Version ohne die Möglichkeit eines Speicherverlusts (bitte überprüfen Sie den Code):
quelle
Die Fehlerbehebung bei Kompilierungsfehlern ist dagegen sehr kompliziert. Diese Probleme manifestieren sich in einer FileNotFoundException mit der Meldung:
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
quelle
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.
quelle
Eine benutzerdefinierte Klasse zum Serialisieren:
Ich habe das Code-Snippet angehängt. Vielleicht kann dir das helfen.
quelle
Ich hatte ein ähnliches Problem und das Ignorieren der Ausnahme funktionierte bei mir nicht. Mein Code hat die Konfiguration von NServiceBus aufgerufen
Configure.With(...).XmlSerializer()...
Was es für mich behoben hat, war, die Plattform für mein Projekt zu ändern.
quelle
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.
Verwendungszweck:
quelle
Ihr Typ verweist möglicherweise auf andere Assemblys, die weder im GAC noch in Ihrem lokalen bin-Ordner gefunden werden können ==> ...
Können Sie ein Beispiel für den Typ geben, den Sie serialisieren möchten?
Hinweis: Stellen Sie sicher, dass Ihr Typ Serializable implementiert.
quelle
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.
quelle
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 ...
quelle
ConcurrentDictionary
Ich 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.Ich habe andere Beiträge gesehen, die den Wert betreffen
ConcurrentDictionary
undLazy
laden. Ich bin mir nicht sicher, ob das hier relevant ist oder nicht, aber hier ist der Code dafür:quelle