Aplikacja, z którą pracuję, zawiesza się, gdy próbuję serializować typy.
Oświadczenie jak
XmlSerializer lizer = new XmlSerializer(typeof(MyType));
produkuje:
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)
Nie definiuję żadnych specjalnych serializatorów dla mojej klasy.
Jak mogę rozwiązać ten problem?
c#
xml-serialization
Irwin
źródło
źródło
Generate serialization assembly
menu rozwijane na „Wł.” Zamiast „Auto”.Odpowiedzi:
Wierzcie lub nie, to jest normalne zachowanie. Wyjątek jest zgłaszany, ale obsługiwany przez XmlSerializer, więc jeśli go zignorujesz, wszystko powinno być w porządku.
Uważam to za bardzo irytujące i było wiele skarg na to, jeśli trochę się rozglądasz, ale z tego, co przeczytałem, Microsoft nie planuje nic z tym zrobić.
Możesz uniknąć wyświetlania wyskakujących okien wyjątków przez cały czas podczas debugowania, jeśli wyłączysz wyjątki pierwszej szansy dla tego konkretnego wyjątku. W programie Visual Studio przejdź do opcji Debugowanie -> Wyjątki (lub naciśnij Ctrl+ Alt+ E), Wyjątki czasu wykonywania wspólnego języka -> System.IO -> System.IO.FileNotFoundException .
Informacje o innym rozwiązaniu można znaleźć w blogu C # XmlSerializer FileNotFound wyjątek (który omawia narzędzie Chrisa Sellsa XmlSerializerPreCompiler ).
źródło
Jak powiedział Martin Sherburn, jest to normalne zachowanie. Konstruktor XmlSerializer najpierw próbuje znaleźć zestaw o nazwie [YourAssembly] .XmlSerializers.dll, który powinien zawierać wygenerowaną klasę do serializacji danego typu. Ponieważ taka biblioteka DLL nie została jeszcze wygenerowana (nie są domyślnie), zgłaszany jest wyjątek FileNotFoundException. Kiedy tak się dzieje, konstruktor XmlSerializer przechwytuje ten wyjątek, a biblioteka DLL jest generowana automatycznie w czasie wykonywania przez konstruktor XmlSerializer (odbywa się to poprzez wygenerowanie plików źródłowych C # w katalogu% temp% na komputerze, a następnie kompilację przy użyciu kompilatora C #). Dodatkowe konstrukcje XmlSerializer dla tego samego typu będą po prostu korzystać z już wygenerowanej biblioteki DLL.
Wyjątek jest obsługiwany przez konstruktor XmlSerializer. Nie musisz nic robić sam, wystarczy kliknąć „Kontynuuj” (F5), aby kontynuować wykonywanie programu i wszystko będzie dobrze. Jeśli przeszkadzają Ci wyjątki, które zatrzymują wykonywanie programu i wyświetlają pomocnika wyjątków, albo masz „Just My Code” wyłączony, albo masz wyjątek FileNotFoundException, który przerywa wykonywanie po rzuceniu, zamiast gdy „User- nieobsługiwany ”.
Aby włączyć „Just My Code”, przejdź do Narzędzia >> Opcje >> Debugowanie >> Ogólne >> Włącz Just My Code. Aby wyłączyć przerwanie wykonywania po wyrzuceniu FileNotFound, przejdź do Debugowanie >> Wyjątki >> Znajdź >> wpisz „FileNotFoundException” >> odznacz pole wyboru „Zgłoszony” w System.IO.FileNotFoundException.
źródło
FileNotFoundException
zostanie wyrzucony. Różnica nie polega na tym, jak sprawdzane jest istnienie złożenia, ale na tym, jak go wygenerować, gdy zostanie ustalone, że go brakuje. Wcześniej używano tekstowego generowania kodu C # z wywołaniem kompilatora C # w celu utworzenia IL. Począwszy od .NET 4.5, emituje IL bezpośrednio, bez użycia kompilatora.File.Exists()
może być niewystarczający. Lokalizowanie zestawu nie jest prostą sprawą, środowisko wykonawcze sprawdza w kilku lokalizacjach i wierzę, że zachowanie zmienia się w zależności od środowiska (aplikacja konsolowa vs. hostowana w IIS itp.). Myślę, że to, co powinno zostać zaimplementowane, byłoTryLoadAssembly()
lub coś podobnego.We właściwościach projektu Visual Studio (strona „Kompiluj”, jeśli dobrze to pamiętam) istnieje opcja „generuj zespół serializacji”. Spróbuj włączyć go dla projektu, który generuje [Zawiera zestaw MyType] .
źródło
Istnieje obejście tego problemu. Jeśli użyjesz
powinien unikać tego wyjątku. To zadziałało dla mnie.
OSTRZEŻENIE: Nie należy używać wielokrotnie, w przeciwnym razie nastąpi wyciek pamięci
Wyciekasz pamięć jak szaloną, jeśli użyjesz tej metody do tworzenia instancji
XmlSerializer
dla tego samego typu więcej niż jeden raz!Wynika to z tego, że ta metoda omija wbudowane buforowanie pod warunkiem, że
XmlSerializer(type)
iXmlSerializer(type, defaultNameSpace)
konstruktorów (wszystkie inne konstruktory również omijają pamięć podręczną).Jeśli użyjesz dowolnej metody, aby utworzyć XmlSerializer, który nie odbywa się za pośrednictwem tych dwóch konstruktorów, musisz zaimplementować własne buforowanie lub pamięć krwotoku.
źródło
XmlSerializer
dla tego samego typu więcej niż jeden raz! Wynika to z tego, że ta metoda omija wbudowane buforowanie pod warunkiem konstruktorówXmlSerializer(type)
iXmlSerializer(type, defaultNameSpace)
(wszystkie inne konstruktory również omijają pamięć podręczną). Jeśli użyjesz dowolnej metody, aby utworzyć narzędzie,XmlSerializer
które nie odbywa się za pośrednictwem tych dwóch konstruktorów, musisz zaimplementować własne buforowanie, w przeciwnym razie pamięć krwotoków zostanie zachowana.FromTypes
wydaje się zapełniać pamięć podręczną. Powinien to być prawidłowy sposób na rozgrzanie pustejXmlSerializer
pamięci podręcznej w jednej instrukcji (jak sugeruje artykuł), ale naprawdę zły sposób na odzyskanie z niej czegokolwiek (powinno się to odbywać tylko za pomocą najprostszych konstruktorów). W każdym razie nie wiedziałem, że to błąd, zawsze myślałem, że wszystko, co wyciek ma wyciec (podobnie jak bardziej zaawansowaneXmlSerializer
konstruktory). Nawet nie pomyślałbym o użyciu,FromTypes()
skoro możesz to zrobićtypes.Select(t => new XmlSerializer(t))
.FromTypes
ma swój urok - nawet jeśli wszystkie zgłoszone wyjątki zostaną złapane, jest to bardzo cenna operacja; podejście „buforuj po swojemu” wydaje się być jedynym obejściem, ponieważ jedyna oficjalnie obsługiwana poprawka wygląda na niejasny zestaw internetowy. (edycja: szczerze mówiąc, jestem za przeniesieniem wszystkiego do kontraktów danych :))Natrafiłem na ten konkretny problem i nie mogłem go obejść za pomocą żadnego z wymienionych rozwiązań.
W końcu znalazłem rozwiązanie. Wygląda na to, że serializator potrzebuje nie tylko typu, ale także typów zagnieżdżonych. Zmieniając to:
Do tego:
Naprawiono problem dla mnie. Nigdy więcej wyjątków lub czegokolwiek.
źródło
var xmlSerializer = new XmlSerializer(typeof(T), typeof(T).GetNestedTypes());
Moim rozwiązaniem jest przejście bezpośrednio do refleksji, aby utworzyć serializator. Pomija to dziwne ładowanie plików, które powoduje wyjątek. Spakowałem to w funkcji pomocniczej, która również zajmuje się buforowaniem serializatora.
źródło
Aby uniknąć wyjątku, musisz zrobić dwie rzeczy:
Dodaj atrybut System.Xml.Serialization.XmlSerializerAssembly do swojej klasy. Zamień „MyAssembly” na nazwę zestawu, w którym znajduje się MyClass.
Wygeneruj plik serializacji za pomocą narzędzia sgen.exe i wdróż go przy użyciu zestawu klasy.
„sgen.exe MyAssembly.dll” wygeneruje plik MyAssembly.XmlSerializers.dll
Te dwie zmiany spowodują, że .net bezpośrednio znajdzie zestaw. Sprawdziłem to i działa na .NET Framework 3.5 z Visual Studio 2008
źródło
Ten wyjątek może również zostać uwięziony przez zarządzanego asystenta debugowania (MDA) o nazwie BindingFailure.
Ta MDA jest przydatna, jeśli aplikacja jest zaprojektowana do dostarczania z kompilacjami serializacji przed kompilacją. Robimy to, aby zwiększyć wydajność naszej aplikacji. Pozwala nam to upewnić się, że wstępnie skompilowane zestawy serializacji są poprawnie budowane przez nasz proces kompilacji i ładowane przez aplikację bez konieczności ponownej kompilacji w locie.
Jest to naprawdę nieprzydatne, z wyjątkiem tego scenariusza, ponieważ jak powiedzieli inni plakaty, gdy konstruktor Serializer uwięził błąd wiązania, zespół serializacji jest ponownie budowany w czasie wykonywania. Więc zazwyczaj możesz to wyłączyć.
źródło
Funkcja XmlSerializer.FromTypes nie zgłasza wyjątku, ale przecieka pamięć. Dlatego musisz buforować taki serializator dla każdego typu, aby uniknąć wycieku pamięci dla każdej utworzonej instancji.
Utwórz własną fabrykę XmlSerializer i użyj jej po prostu:
Fabryka wygląda jak:
Bardziej skomplikowana wersja bez możliwości wycieku pamięci (proszę przejrzeć kod):
źródło
Z drugiej strony rozwiązywanie problemów z kompilacją jest bardzo skomplikowane. Te problemy przejawiają się w wyjątku FileNotFoundException z komunikatem:
Możesz się zastanawiać, co wyjątek związany z nie znalezieniem pliku ma związek z tworzeniem wystąpienia obiektu serializującego, ale pamiętaj: konstruktor zapisuje pliki C # i próbuje je skompilować. Stos wywołań tego wyjątku dostarcza pewnych dobrych informacji na poparcie tego podejrzenia. Wystąpił wyjątek, gdy XmlSerializer próbował załadować zestaw wygenerowany przez CodeDOM wywołujący metodę System.Reflection.Assembly.Load. Wyjątek nie wyjaśnia, dlaczego zestaw, który miał utworzyć XmlSerializer, nie był obecny. Ogólnie rzecz biorąc, zestaw nie jest obecny, ponieważ kompilacja nie powiodła się, co może się zdarzyć, ponieważ w rzadkich okolicznościach atrybuty serializacji generują kod, którego kompilator C # nie kompiluje.
Uwaga Ten błąd występuje również, gdy XmlSerializer działa na koncie lub w środowisku bezpieczeństwa, które nie ma dostępu do katalogu tymczasowego.
Źródło : http://msdn.microsoft.com/en-us/library/aa302290.aspx
źródło
We właściwościach projektu Visual Studio istnieje opcja „generuj zespół serializacji”. Spróbuj włączyć go dla projektu, który generuje [Zawiera zestaw MyType].
źródło
Klasa niestandardowa do serializacji:
Załączam fragment kodu. Może to może ci pomóc.
źródło
Miałem podobny problem i zignorowanie wyjątku nie zadziałało. Mój kod wywoływał konfigurację NServiceBus
Configure.With(...).XmlSerializer()...
Naprawdę zmieniłem platformę mojego projektu.
źródło
Tylko jako odniesienie. Biorąc od DB odpowiedzi i komentarze, przyszedłem z tym rozwiązaniem, które jest zbliżone do rozwiązania DB. Działa dobrze we wszystkich moich przypadkach i jest bezpieczny dla wątków. Nie sądzę, że użycie ConcurrentDictionary byłoby w porządku.
Stosowanie:
źródło
Twój typ może odwoływać się do innych zespołów, których nie można znaleźć ani w GAC, ani w lokalnym folderze bin ==> ...
Czy możesz podać przykład typu, który chcesz serializować?
Uwaga: Upewnij się, że Twój typ implementuje Serializable.
źródło
Otrzymywałem ten sam błąd i wynikało to z typu, którego próbowałem deserializować, nie mając domyślnego konstruktora bez parametrów . Dodałem konstruktor i zaczął działać.
źródło
Miałem ten sam problem, dopóki nie użyłem narzędzia innej firmy do wygenerowania klasy z XSD i zadziałało! Odkryłem, że narzędzie dodawało dodatkowy kod na początku mojej klasy. Kiedy dodałem ten sam kod na początku mojej oryginalnej klasy, zadziałało. Oto co dodałem ...
źródło
Widziałem wiele rekomendacji do użycia
ConcurrentDictionary
, ale nie ma solidnych przykładów, więc wrzucę swój kapelusz w ten wyścig rozwiązań. Nie jestem programistą bezpiecznym dla wątków, więc jeśli ten kod nie jest solidny, proszę zabrać głos ze względu na tych, którzy go śledzą.Widziałem inne posty obejmujące
ConcurrentDictionary
iLazy
ładujące wartość. Nie jestem pewien, czy jest to istotne tutaj, czy nie, ale oto kod do tego:źródło