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
Хорошо, так что этот вопрос - только моя версия CB из уже заданного вопроса VB: stackoverflow.com/questions/294659/… Спасибо, ребята.
Ирвин
1
Шесть лет спустя ответ @VladV - самое простое и наименее неблагоприятное решение. Просто измените Generate serialization assemblyраскрывающийся список на «Вкл» вместо «Авто».
Heliac
@ Helic: я не согласен. Не всегда получается. Пожалуйста, смотрите комментарий Бенуа Бланшона к ответу Влада. Самый простой ответ для меня - не использовать String.Collection в конфигурационных файлах. Вместо этого я использую: string [] items = Settings.Default.StringofNewlineDelimitedItems.Split (new [] {Environment.NewLine});
Эндрю Деннисон

Ответы:

388

Верьте или нет, это нормальное поведение. Исключение выдается, но обрабатывается XmlSerializer, поэтому, если вы просто игнорируете его, все должно продолжаться в порядке.

Я нахожу это очень раздражающим, и было много жалоб по этому поводу, если вы будете немного искать, но из того, что я прочитал, Microsoft не планирует что-либо делать с этим.

Вы можете избежать появления всплывающих окон Исключения во время отладки, если отключите исключения первого шанса для этого конкретного исключения. В Visual Studio перейдите в « Отладка -> Исключения (или нажмите Ctrl+ Alt+ E)», « Исключения времени выполнения общего языка -> System.IO -> System.IO.FileNotFoundException» .

Информацию об этом можно найти в посте C # XmlSerializer FileNotFound исключение (где обсуждается инструмент Криса Селлса 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» >> снимите флажок «Брошено» в System.IO.FileNotFoundException.

Аллон Гуралнек
источник
+1 за обновление: это объясняет другое поведение при отладке тестовых случаев
mbx
3
Ваше обновление предполагает, что это исключение не должно появляться в .NET 4.5, но я все еще вижу его.
Тимбо
@ Тимбо: я не понимаю, почему вы не получите это исключение с .NET 4.5. Он по-прежнему ищет файл, и если файл отсутствует, FileNotFoundExceptionбудет выброшен. Разница заключается не в том, как проверяется наличие сборки, а в том, как ее сгенерировать, если определено, что она отсутствует. Раньше он использовал генерацию текстового кода C # с вызовом компилятора C # для создания IL. Начиная с .NET 4.5, он излучает IL напрямую, без использования компилятора.
Аллон Гуралнек
1
Я просто хотел бы, чтобы MS реализовала это так, как если бы (File.Exists (...)) {Load} else {Fallback} вместо попытки {Load} catch {Fallback}. Управление потоком на основе исключений плохо пахнет и делает мой опыт отладки более сложным и ломким, чем необходимо.
Тимбо
1
@ Тимбо: простого File.Exists()может быть недостаточно. Поиск сборки не является простым делом, среда выполнения просматривает несколько мест, и я считаю, что поведение меняется в зависимости от среды (консольное приложение по сравнению с размещением в IIS и т. Д.). Я думаю, что должно было быть реализовано TryLoadAssembly()или что-то подобное.
Аллон Гуралнек
63

В свойствах проекта Visual Studio (на странице «Сборка», если я правильно помню) есть опция «создать сборку сериализации». Попробуйте включить его для проекта, который генерирует [Содержащий сборку MyType] .

VladV
источник
4
Также см. Stackoverflow.com/a/8798289/1164966, если сборка сериализации все еще не сгенерирована Visual Studio.
Бенуа Бланшон
Лучший, четкий, лаконичный ответ! Я бы тоже хотел проголосовать снова!
Джон Заброски
59

Для этого есть обходной путь. Если вы используете

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

следует избегать этого исключения. Это сработало для меня.

ВНИМАНИЕ: не используйте несколько раз, иначе у вас будет утечка памяти

Вы потеряете память как сумасшедшую, если будете использовать этот метод для создания экземпляров одного и XmlSerializerтого же типа более одного раза!

Это связано с тем, что этот метод обходит встроенное кэширование, предоставляемое конструкторами XmlSerializer(type)and XmlSerializer(type, defaultNameSpace)(все остальные конструкторы также обходят кэш).

Если вы используете какой-либо метод для создания XmlSerializer, который не использует эти два конструктора, вы должны реализовать собственное кэширование, иначе у вас будет кровоизлияние в память.

quadfinity
источник
44
ВНИМАНИЕ: Вы потеряете память как сумасшедшую, если будете использовать этот метод для создания экземпляров одного и XmlSerializerтого же типа более одного раза! Это связано с тем, что этот метод обходит встроенное кэширование, предоставляемое конструкторами XmlSerializer(type)and 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имеет свою привлекательность - даже если все исключения выявляются, это дорогостоящая операция; подход «кэшируйте по-своему», кажется, является единственным обходным решением, поскольку единственное официально поддерживаемое исправление выглядит в неясной веб-сборке. (отредактируйте: откровенно говоря, я весь за то, что
перенес
23

Я столкнулся с этой проблемой и не мог обойти ее ни одним из упомянутых решений.

Тогда я наконец нашел решение. Похоже, что сериализатору нужен не только тип, но и вложенные типы. Меняем это:

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());
user3161729
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 динамически генерирует сборки для сериализации и десериализации указанных типов. Каркас находит и использует эти сборки. Это происходит только при использовании следующих каторов: XmlSerializer.XmlSerializer (Type) XmlSerializer.XmlSerializer (Type, String) Ссылка: msdn.microsoft.com/en-us/library/…
Дейв Блэк
@DaveBlack: Да, но эти конструкторы выдают и ловят исключение внутри, даже когда использование полностью допустимо. Это плохо, и именно поэтому ОП задала вопрос в первую очередь.
д - б
@db Верно, но то, что я хотел сказать (но не ясно - мои извинения), было то, что единственные строки вашего soln, которые необходимы, - это первые 3 строки в состоянии else.
Дэйв Блэк,
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 полезен, если ваше приложение предназначено для поставки с предварительно собранными сериализованными сборками. Мы делаем это для повышения производительности нашего приложения. Это позволяет нам убедиться в том, что предварительно собранные сборки сериализации правильно собираются нашим процессом сборки и загружаются приложением без повторной сборки на лету.

Это действительно бесполезно, за исключением этого сценария, потому что, как говорили другие авторы, когда ошибка связывания перехватывается конструктором Serializer, сборка сериализации перестраивается во время выполнения. Так что обычно вы можете выключить его.

HiredMind
источник
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
Как это может заблокировать, если все управление со словарем находится в разделе блокировки?
Томас Кубес
Извините, я перепутал слова. Я имел в виду, что он может вставить элемент более одного раза. потому что существует разрыв между тем, когда он проверяет существование и когда он вставляет. словарь одновременной работы использует своего рода двухфазную блокировку (bag [0], а затем bag [hash]]) и сохраняет ссылку на сумку, в которую необходимо вставить / содержать элемент, с которым вы работаете. Это быстрее, безопаснее и чище.
Behrooz
Да и нет. Вы правы, что может случиться так, что в одно и то же время один сериализатор одного типа будет создан на двух потоках параллельно, а затем добавлен в словарь дважды. В этом случае вторая вставка просто заменит первую, но секция замка гарантирует безопасность резьбы, а общий недостаток - небольшая утечка памяти. Это оптимизация производительности, потому что вы не хотите, чтобы один поток с сериализатором типа 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

Zyphrax
источник
он не уточнил, что это произошло во время выполнения. Еще одна вещь, о которой я могу думать, это то, что у вас, возможно, конфликт пространства имен / класса. Какое полное имя вашего MyType?
Zyphrax
Да, я проверил вашу ссылку, информация о конструкторах, хотя и полезная, была не тем, что мне было нужно.
Ирвин
5
@SpaceghostAl Вы можете скомпилировать во время выполнения. И это то, что делает XmlSerializer. Во время выполнения он динамически создает сборку, которая (де) сериализует XML для определенного типа. По какой-то причине этот процесс не удается для OP. Вероятно, из-за проблем с правами доступа, например, во временном каталоге. (Может быть так же глупо, как даже из дискового пространства.)
Nos
вы уверены в этом? Я был уверен , что сериализация материал компилируется в сборку с именем YourAssemblyName.XmlSerializers.dll во время сборки , а не компилируются во время выполнения. Это может привести к сбою по разным причинам, хотя бы из-за всех разрешений NTFS в папке развертывания.
Tomfanning
1
Хотелось бы, чтобы я проголосовал за это несколько раз. Ваше сообщение о том, что аккаунт не может получить доступ к временной папке, вызвало ответ для меня. Как только я добавил свою служебную учетную запись в группу администраторов на сервере, она просто заработала. Спасибо!
Боб Хорн
2

В свойствах проекта Visual Studio есть опция «генерировать сборку сериализации». Попробуйте включить его для проекта, который генерирует [Содержащий сборку 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();
}
shahjapan
источник
2
-1 за отсутствие использования блоков для предотвращения утечек ресурсов и за использование XmlTextWriter.
Джон Сондерс
хорошо, согласен, но все же я использовал XmlSerializer xmlSerializer = new XmlSerializer (typeof (TestClass)); но я не получаю указанное исключение.
Шахджапан
1

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

Для меня это было связано с изменением платформы для моего проекта.

  1. Перейдите в Build \ Configuration Manager ...
  2. Найдите свой проект и поменяйте платформу (в моем случае с x86 на любой процессор)
kkelley
источник
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
  {
  ...
TheJonz
источник
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;
}
Airn5475
источник