XmlSerializer дає FileNotFoundException у конструкторі


347

Програма, з якою я працював, не працює, коли я намагаюся серіалізувати типи.

Заява на кшталт

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

виробляє:

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)

Я не визначаю жодних спеціальних серіалізаторів для свого класу.

Як я можу виправити цю проблему?


5
Гаразд, тож це питання - лише моя C # версія вже заданого питання VB: stackoverflow.com/questions/294659/… Дякую, хлопці.
Ірвін

1
Шість років далі відповідь @VladV - це найпростіший і найменш негативний вплив. Просто змініть Generate serialization assemblyспадне меню на "Увімкнено", а не на "Автоматично".
Геліак

@Heliac: Я не згоден. Це не завжди працює. Будь ласка, дивіться коментар Бенуа Бланшона до відповіді Влада. Найпростіша відповідь для мене - не використовувати String.Collection у конфігураційних файлах. Натомість я використовую: string [] items = Settings.Default.StringofNewlineDelimitedItems.Split (new [] {Environment.NewLine});
Ендрю Деннісон

Відповіді:


388

Вірите чи ні, це нормальна поведінка. Виняток кидається, але XmlSerializer обробляє, але якщо ви просто ігноруєте його, все має продовжуватися.

Я вважаю це дуже дратівливим, і було багато скарг на це, якщо трохи пошукати, але з того, що я прочитав, Microsoft не планує нічого з цим робити.

Ви можете уникнути отримання спливаючих вікон Exception весь час під час налагодження, якщо вимкнути винятки з першого шансу для цього конкретного винятку. У візуальній студії перейдіть до програми налагодження -> Винятки (або натисніть Ctrl+ Alt+ E), Винятки з загальної мови для виконання -> System.IO -> System.IO.FileNotFoundException .

Ви можете знайти інформацію про інший спосіб її вирішення у випуску блогу C # XmlSerializer FileNotFound (де обговорюється інструмент Chris Sells XmlSerializerPreCompiler ).


162
Один із можливих способів позбутися цієї проблеми - це встановити прапорець "Просто мій код" в меню Інструменти -> Параметри -> Налагодження -> Загальні параметри.
Фредерік

26
@Frederic: Цей коментар є приголомшливим! Я сиджу тут із "WTF !?" вираз на моєму обличчі, намагаючись вгамувати цей хибний виняток, і я знаходжу це питання з відповіддю (це вина Microsoft, що ще нового?), але я не хотів відключати обробку винятків, тому що мені це може знадобитися для мій код. A +!
Кумба

27
Я думаю, що пропозиція Ганса нижче є більш цінною - використовуйте інший виклик методу, який зовсім не створює цього винятку: XmlSerializer serializer = XmlSerializer.FromTypes (new [] {typeof (MyType)}) [0];
яскравий

3
Проблема полягає в тому, що це не дає мого тесту, тому я не можу просто «ігнорувати» виняток
Csaba Toth

16
Перепрошую, але це жахлива пропозиція. На мій досвід FileNotFoundException - одна з найпоширеніших, і вимкнення цього звіту про виключення - це просто запит на проблему колись у майбутньому. Краще ввімкнути "Просто мій код" або дозволити створення збірок серіалізації, описаних нижче.
Quarkly

104

Як сказав Мартін Шерберн, це нормальна поведінка. Конструктор XmlSerializer спочатку намагається знайти збірку під назвою [YourAssembly] .XmlSerializers.dll, яка повинна містити створений клас для серіалізації вашого типу. Оскільки така DLL ще не створена (вони за замовчуванням не є), передається FileNotFoundException. Коли це трапляється, конструктор XmlSerializer ловить це виняток, і DLL створюється автоматично під час виконання конструктором XmlSerializer (це робиться шляхом генерування вихідних файлів C # у каталозі% temp% вашого комп'ютера, а потім їх компіляції за допомогою компілятора C #). Додаткові конструкції XmlSerializer для одного типу просто використовуватимуть вже створену DLL.

ОНОВЛЕННЯ: Починаючи з .NET 4.5, він XmlSerializerбільше не виконує генерацію коду, а також не здійснює компіляцію з компілятором C # для того, щоб створити збірку серіалізатора під час виконання, якщо явно не змушений це встановити налаштування файлу конфігурації ( useLegacySerializerGeneration ). Ця зміна усуває залежність від csc.exeта покращує продуктивність запуску. Джерело: .NET Framework 4.5 Readme , розділ 1.3.8.1.

Виняток обробляє конструктор XmlSerializer. Не потрібно нічого робити самостійно, ви можете просто натиснути «Продовжити» (F5), щоб продовжити виконання вашої програми, і все буде добре. Якщо вас турбують винятки, що зупиняють виконання вашої програми та вискакують помічник виключення, у вас або вимкнено "Просто мій код", або у вас встановлено FileNotFoundException, щоб порушити виконання при видаленні, а не коли "Користувач- необроблений '.

Щоб увімкнути "Просто мій код", перейдіть до Інструменти >> Опції >> Налагодження >> Загальне >> Увімкнути Просто мій код. Щоб вимкнути порушення виконання при передачі FileNotFound, перейдіть до Налагодження >> Винятки >> Знайти >>, введіть “FileNotFoundException” >>, зніміть прапорець “Thrown” від System.IO.FileNotFoundException.


+1 для оновлення: це пояснює різну поведінку під час налагодження тестових випадків
mbx

3
Оновлення передбачає, що цей виняток не має відбуватися в .NET 4.5, але я все ще бачу його.
Тімбо

@Timbo: Я не розумію, чому ви не отримали б це виключення за допомогою .NET 4.5. Він як і раніше шукає файл, і якщо файл відсутній, FileNotFoundExceptionбуде викинуто а. Різниця полягає не в тому, як перевіряється існування збірки, а в тому, як генерувати її, як тільки буде визначено, що вона відсутня. Раніше воно використовувало текстове генерацію коду C # з викликом компілятора C # для створення IL. Починаючи з .NET 4.5, він випромінює IL безпосередньо, без використання компілятора.
Аллон Гуралнек

1
Я просто хочу, щоб MS реалізувала це так, як якщо б (File.Exists (...)) {Load} else {Fallback} замість того, щоб спробувати {Load} catch {Fallback}. Контроль потоку на основі винятку погано пахне і робить мій досвід налагодження складнішим і крихким, ніж потрібно.
Тімбо

1
@Timbo: простого File.Exists()може бути недостатньо. Розташування збірки не є простою справою, час виконання виглядає в декількох місцях, і я вважаю, що поведінка змінюється залежно від середовища (консольний додаток проти розміщення в IIS тощо). Я здогадуюсь, що мало бути реалізовано, TryLoadAssembly()чи щось подібне.
Аллон Гуралнек

63

У властивостях проекту Visual Studio (сторінка "Build", якщо я пам'ятаю це правильно) є опція, що говорить "генерувати серіалізаційну збірку". Спробуйте ввімкнути його для проекту, який генерує [Contain Assembly of MyType] .


4
Також дивіться stackoverflow.com/a/8798289/1164966, якщо збірка серіалізації все ще не генерується Visual Studio.
Бенуа Бланшон

Найкраща, найясніша, лаконічна відповідь! Я б хотів, щоб я міг проголосувати ще раз!
Джон Заброскі

59

Для цього існує рішення. Якщо ви використовуєте

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

слід уникати цього винятку. Це працювало для мене.

ПОПЕРЕДЖЕННЯ: Не використовуйте кілька разів, інакше у вас буде витік пам'яті

Ви просочите пам’ять, як божевільна, якщо ви використовуєте цей метод для створення екземплярів XmlSerializerодного типу не один раз!

Це пояснюється тим, що цей метод обходить вбудований кешування, передбачений XmlSerializer(type)і XmlSerializer(type, defaultNameSpace)конструкторами (всі інші конструктори також обходять кеш).

Якщо ви використовуєте будь-який метод для створення XmlSerializer, який не відбувається за допомогою цих двох конструкторів, ви повинні реалізувати власне кешування або ви пам’ятаєте крововиливи.


44
ПОПЕРЕДЖЕННЯ: Ви будете просочувати пам'ять як божевільний, якщо цей метод будете створювати екземпляри XmlSerializerодного типу не один раз! Це пояснюється тим, що цей метод обходить вбудований кешування, передбачений XmlSerializer(type)і XmlSerializer(type, defaultNameSpace)конструкторами (всі інші конструктори також обходять кеш). Якщо ви використовуєте будь-який метод для створення цього, XmlSerializerякий не відбувається за допомогою цих двох конструкторів, ви повинні реалізувати власне кешування, або ви пам’ятаєте крововиливи.
Аллон Гуралнек

4
@AllonGuralnek Ну я буду проклятий ... ти абсолютно прав; Подальше копання через Reflector показує, що, хоча він перевіряє кеш, він робить це після створення збірки серіалізації! Wtf?!?
JerKimball

4
Виявляється відома помилка: weblogs.asp.net/cschittko/archive/2005/01/14/353435.aspx
JerKimball

3
@JerKimball: Ця сторінка насправді не бреше. Як ви виявили, FromTypesсхоже, це заповнення кешу. Таким чином, це повинен бути дійсним способом розігріти порожній XmlSerializerкеш в одному висловлюванні (як це пропонує стаття), але дійсно поганий спосіб отримати що-небудь з нього (це слід робити лише через найпростіші конструктори). У будь-якому випадку, я не знав, що це помилка, я завжди вважав, що все, що може витікати, протікає (як і більш просунуті XmlSerializerконструктори). Я б навіть не думав використовувати, FromTypes()оскільки ви просто можете це зробити types.Select(t => new XmlSerializer(t)).
Аллон Гуралнек

2
@AllonGuralnek Не зондуючий аспект використання FromTypesмає свою привабливість - навіть через викинуті винятки все спіймано, це дорога операція; підхід "кешувати свій власний шлях" є єдиним вирішенням, оскільки єдиний офіційно підтримуваний виправлення виглядає в незрозумілому веб-зборі. (відредагувати: відверто кажучи, я все за те, щоб перенести все на договори з даними :))
JerKimball

22

Я зіткнувся з цією проблемою і не зміг її обійти жодним із згаданих рішень.

Тоді я нарешті знайшов рішення. Виявляється, серіалізатору потрібен не лише тип, а й вкладені типи. Зміна цього:

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

До цього:

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

Виправлена ​​проблема для мене. Більше немає винятків чи нічого.


8
Це працювало для мене. Використовуючи .Net4.0 формат єvar xmlSerializer = new XmlSerializer(typeof(T), typeof(T).GetNestedTypes());
користувач3161729

1
Це працювало і для мене. Але це здається необхідним лише при серіалізації, а не при десеріалізації. Можливо, це має сенс, можливо, це не так.
SteveCinq

2
Це також призводить до витоку пам'яті, якщо працювати багато разів.
Володимир Котило

9

Моє рішення - перейти до роздумів, щоб створити серіалізатор. Це обходить дивне завантаження файлів, що викликає виняток. Я упакував це в допоміжну функцію, яка також піклується про кешування серіалізатора.

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;
    }
}

Тут є дві проблеми - по-перше, ваш код не є безпечним для потоків, а по-друге (що важливіше) ви намагаєтесь повторити те, що вже працює .net (на основі ctor, який ви використовуєте). тобто немає необхідності в цьому коді
Дейв Блек

@DaveBlack: Так, відповідь quadfinity із кешуванням на ConcurrentDictionary буде краще
d - b

@db Мій другий пункт полягав у тому, що кешування навіть не потрібно - доки ви використовуєте один із 2-х цитових, які кешують каркас (OP використовує перший). Від MSDN: для підвищення продуктивності інфраструктура серіалізації XML динамічно генерує збірки для серіалізації та десеріалізації зазначених типів. Рамка знаходить і повторно використовує ці збори. Така поведінка виникає лише при використанні таких ctors: XmlSerializer.XmlSerializer (Type) XmlSerializer.XmlSerializer (тип, рядок) Довідка: msdn.microsoft.com/en-us/library/…
Дейв Блек

@DaveBlack: Так, але ці конструктори викидають і виловлюють виняток всередині, навіть коли використання є повністю дійсним. Це погано, і це причина, чому ОП задала питання в першу чергу.
d - b

@db Щоправда, але те, що я мав намір сказати (але не було зрозуміло - мої вибачення), це те, що єдині необхідні рядки вашого soln - це перші 3 рядки в іншій умові.
Дейв Блек

8

Щоб уникнути винятку, вам потрібно зробити дві речі:

  1. Додайте атрибут до серіалізованого класу (сподіваюся, у вас є доступ)
  2. Створіть файл серіалізації за допомогою sgen.exe

Додайте до свого класу атрибут System.Xml.Serialization.XmlSerializerAssembly. Замініть "MyAssembly" на назву збірки, де знаходиться MyClass.

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

}

Створіть файл серіалізації за допомогою утиліти sgen.exe і розгорніть його за допомогою складання класу.

'sgen.exe MyAssembly.dll' створить файл MyAssembly.XmlSerializers.dll

Ці дві зміни змусять .net безпосередньо знайти збірку. Я перевірив це, і він працює на .NET Framework 3.5 з Visual Studio 2008


Гаразд, і чи не вдалося це зробити без цих змін, і якщо так, то чому?
Джон Сондерс

1
Я не можу знайти жодної причини, чому мій проект, 4.0 в VS2012, раптом почав провалюватися. "Ігнорування" помилки не була можливою, оскільки вона виникала щоразу, коли я намагався отримати доступ до Active Directory; таким чином ігнорування означатиме не автентифікацію. Я все ще дуже засмучений тим, що VS2012 не автоматично створить DLL для серіалізації належним чином. Однак ці кроки забезпечили ідеальне рішення.
sfuqua

6

Цей виняток може бути захоплений керованим помічником налагодження (MDA) під назвою BindingFailure.

Цей MDA корисний, якщо ваша програма призначена для постачання з попередньою збіркою серіалізаційних збірок. Ми робимо це для підвищення продуктивності нашого додатку. Це дозволяє нам переконатися, що заздалегідь складені збірки серіалізації будуються належним чином нашим процесом збирання та завантажуються додатком, не будуючи його знову на ходу.

Це справді не корисно, окрім цього сценарію, оскільки, як говорили інші афіші, коли конструктор серіалізатора вловлює помилку прив'язки, збірка серіалізації відновлюється під час виконання. Тож зазвичай можна вимкнути це.


6

Функція XmlSerializer.FromTypes не кидає винятку, але вона просочує пам'ять. Ось чому вам потрібно кешувати такий серіалізатор для кожного типу, щоб уникнути протікання пам'яті для кожного створеного екземпляра.

Створіть власну фабрику XmlSerializer і використовуйте її просто:

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

Фабрика виглядає так:

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;
    }       
}

Більш складна версія без можливості витоку пам'яті (будь-хто перегляне код):

    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;
    }       
}

Ви повинні використовувати ConcurrentDictionary замість цього. Цей код може зайти в тупик.
Behrooz

Як це зробити в глухому куті, якщо все управління зі словником знаходиться в розділі блокування?
Томаш Кубес

Вибачте, слова я переплутав. Я мав на увазі те, що він може вставляти предмет не один раз. оскільки існує розрив між тим, коли він перевіряє наявність і коли він вставляється. паралельний словник використовує якусь двофазну блокування (мішок [0], а потім мішок [хеш]]) і зберігає посилання на сумку, яка повинна вставляти / містити предмет, який ви працюєте. Це швидше, безпечніше і чистіше.
Бехроз

Так і ні. Ви маєте рацію, що може статися, що за той самий час один серіалізатор одного типу буде створений на двох потоках паралельно, а потім два рази доданий до словника. У такому випадку друга вставка просто замінить першу, але блокувальна секція гарантує безпеку різьби та загальним недоліком є ​​невеликий витік пам'яті. Це оптимізація продуктивності, тому що ви не хочете, щоб один потік із серіалізатором типу A чекав, блокується потоком два із серіалізатором типу B у реальному сценарії.
Томаш Кубес

Я можу уявити, що рішення може бути навіть кращим (без теоретичної протікання пам'яті), але складнішим.
Томаш Кубес

3

Виправлення помилок компіляції, з іншого боку, дуже складне. Ці проблеми виявляються у FileNotFoundException з повідомленням:

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() 

Вам може бути цікаво, що стосується файлу, не знайденого винятку, пов’язаного із створенням об'єкта серіалізатора, але пам’ятайте: конструктор записує файли C # та намагається їх компілювати. Стік викликів цього винятку надає хорошу інформацію на підтвердження цієї підозри. Виняток стався, коли XmlSerializer намагався завантажити збірку, згенеровану CodeDOM, викликаючи метод System.Reflection.Assembly.Load. Виняток не дає пояснення, чому збірки, яку повинен був створити XmlSerializer, не було. Загалом, збірки немає, тому що компіляція не вдалася, що може статися, оскільки за рідкісних обставин атрибути серіалізації виробляють код, який компілятор C # не може скомпілювати.

Примітка. Ця помилка також виникає, коли XmlSerializer працює під обліковим записом або середовищем безпеки, яке не в змозі отримати доступ до тимчасового каталогу.

Джерело : http://msdn.microsoft.com/en-us/library/aa302290.aspx


він не уточнив, що це відбувається під час виконання. Інша річ, про яку я можу подумати - це те, що, можливо, у вас конфлікт простору імен / класів. Яке повне ім’я вашого MyType?
Zyphrax

Так, я перевірив ур-посилання, інформація про конструктори, хоч і корисна, була не тим, що мені потрібно.
Ірвін

5
@SpaceghostAl Ви можете компілювати під час виконання. І саме це робить XmlSerializer. Він динамічно будує під час виконання збірку, яка (де) серіалізує XML для конкретного типу. З будь-якої причини цей процес не працює для ОП. Можливо, через проблеми з дозволом, наприклад, у тимчасовій директорії. (Можливо, так само нерозумно, як і з місця на диску.)
неділя

Ви впевнені в цьому? Я був майже впевнений, що матеріали серіалізації збираються в збірку з назвою YourAssemblyName.XmlSerializers.dll під час збирання , а не компілюються під час виконання. Це може бути невдалим з різного роду причин, найменше всіх дозволів NTFS у папці розгортання.
tomfanning

1
Я б хотів, щоб я міг підтвердити це кілька разів. Ваша примітка про те, що обліковий запис не може отримати доступ до темп-папки, викликала для мене відповідь. Після того, як я додав обліковий запис служби в групу адміністратора на сервері, він просто працював. Дякую!
Боб Хорн

2

У властивостях проекту Visual Studio є опція, що говорить "створити збірку серіалізації". Спробуйте ввімкнути його для проекту, який генерує [Contain Assembly of MyType].


1

Спеціальний клас для серіалізації:

[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;
    }
}

Я додав фрагмент коду. Можливо, це може вам допомогти.

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();
}

2
-1 за відсутність використання блоків для запобігання витоку ресурсів та для використання XmlTextWriter.
Джон Сондерс

Добре погоджуюся, але все ж я використовував XmlSerializer xmlSerializer = новий XmlSerializer (typeof (TestClass)); але я не отримую зазначеного Винятку.
shahjapan

1

У мене були подібні проблеми, і ігнорування винятку не працювало для мене. Мій код викликав конфігурацію NServiceBusConfigure.With(...).XmlSerializer()...

Для мене це вирішило - змінити платформу для мого проекту.

  1. Перейдіть до програми Build \ Configuration Manager ...
  2. Знайдіть свій проект та змініть платформу (в моєму випадку з x86 на будь-який процесор)

1

Так само як довідник. Беручи відповіді та коментарі БД, я прийшов із цим рішенням, близьким до рішення БД. Він працює чудово у всіх моїх випадках і безпечний для потоків. Я не думаю, що використання ConcurrentDictionary було б добре.

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;
            }
        }
    }
}

Використання:

        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);
                }
            }
        }

0

Ваш тип може посилатися на інші збірки, які не можна знайти ні в GAC, ні у вашій локальній папці bin ==> ...

"або одна із її залежностей. Система не може знайти вказаний файл"

Чи можете ви навести приклад типу, який ви хочете серіалізувати?

Примітка. Переконайтеся, що ваш тип реалізує Serializable.


0

Я отримував таку ж помилку, і це було пов’язано з типом, який я намагався десеріалізувати, не маючи конструктора без параметрів за замовчуванням . Я додав конструктор, і він почав працювати.


0

У мене була така ж проблема, поки я не використовував інструмент сторонньої сторони для створення класу з XSD, і він працював! Я виявив, що інструмент додає додатковий код у верхній частині мого класу. Коли я додав цей самий код до початку мого оригінального класу, він працював. Ось що я додав ...

#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
  {
  ...

0

Було багато рекомендацій по використанню ConcurrentDictionary, але немає твердих прикладів цього, тому я збираюся закинути шапку в цю гонку рішення. Я не є безпечним для розробників потоків, тому якщо цей код не є надійним, просимо говорити заради тих, хто слідує за ним.

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);
        });
    }
}

Я бачив інші публікації, що стосуються ConcurrentDictionaryта Lazyзавантажують значення. Я не впевнений, це актуально тут чи ні, але ось код для цього:

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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.