XmlSerializer не давая исключение filenotfoundexception в конструктор
приложение, с которым я работал, терпит неудачу, когда я пытаюсь сериализовать типы.
заявления
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)
Я не определяю никаких специальных сериализаторов для моего класса.
Как я могу исправить эту проблему?
17 ответов:
Верьте или нет, это нормальное поведение. Исключение выбрасывается, но обрабатывается XmlSerializer, поэтому, если вы просто игнорируете его, все должно продолжаться нормально.
Я нашел это очень anoying, и было много жалоб на это, если вы немного поищете, но из того, что я прочитал, Microsoft не планирует ничего с этим делать.
вы можете избежать получения исключения всплывающие окна все время во время отладки, если вы отключите первый шанс исключения для этого конкретного исключения. В Visual Studio перейдите в раздел Debug ->исключения (или нажмите клавишу Ctrl + Alt + E),Исключения Общеязыковой Среды Выполнения ->
обновление: начиная с .NET 4.5,
XmlSerializerбольше не выполняет генерацию кода и не выполняет компиляцию с компилятором C# для создания сборки сериализатора во время выполнения, если явно не принудительно чтобы, установив параметр файла конфигурации (useLegacySerializerGeneration). Это изменение устраняет зависимость отcsc.exeи повышает производительность запуска. Источник: .NET Framework 4.5 Readme раздел 1.3.8.1.исключение обрабатывается конструктором XmlSerializer. Нет необходимости делать что-либо самостоятельно, вы можете просто нажать "Продолжить" (F5), чтобы продолжить выполнение вашей программы и все будет штраф. Если вас беспокоят исключения, останавливающие выполнение вашей программы и всплывающие помощники исключений, у вас либо отключен "только мой код", либо у вас есть исключение FileNotFoundException, которое прерывает выполнение при запуске, а не когда "пользователь-необработанный".
чтобы включить "только мой код", перейдите в меню Сервис >> Параметры >> отладка >> общие >> включить только мой код. Чтобы отключить прерывание выполнения при запуске FileNotFound, перейдите в раздел отладка > > исключения > > найти > > ввод 'Исключение filenotfoundexception' >> убираем флажок выбрасываться из системы.ИО.Исключение filenotfoundexception.
в свойствах проекта Visual Studio (страница "сборка", если я правильно помню) есть опция"создать сборку сериализации". Попробуйте включить его для проекта, который генерирует [содержащий сборку MyType].
есть обходной путь для этого. Если вы используете
XmlSerializer lizer = XmlSerializer.FromTypes(new[] { typeof(MyType) })[0];он должен избегать этого исключения. Это сработало для меня.
предупреждение:не используйте несколько раз, или у вас будет утечка памяти
вы будете утечка памяти, как сумасшедший, если вы используете этот метод для создания экземпляров
XmlSerializerдля одного и того же типа более одного раза!это потому, что этот метод обходит встроенное кэширование при условии
XmlSerializer(type)иXmlSerializer(type, defaultNameSpace)конструкторы (все остальные конструкторы также обходят кэш).если вы используете какой-либо метод для создания XmlSerializer, который не используется с помощью этих двух конструкторов, вы должны реализовать свое собственное кэширование, иначе вы потеряете память.
я столкнулся с этой точной проблемой и не мог обойти ее ни одним из упомянутых решений.
тогда я, наконец, нашел решение. Похоже, что сериализатор нуждается не только в типе, но и во вложенных типах. Изменение этого:
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));для этого:
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T).GetNestedTypes());Исправлена проблема для меня. Больше никаких исключений или чего-то еще.
мое решение - перейти прямо к отражению, чтобы создать сериализатор. Это обходит странную загрузку файла, которая вызывает исключение. Я упаковал это в вспомогательную функцию, которая также заботится о кэшировании сериализатора.
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; } }
чтобы избежать исключения, что вам нужно сделать две вещи:
- добавить атрибут к сериализованному классу (я надеюсь, что у вас есть доступ)
- создайте файл сериализации с помощью sgen.exe
добавить системы.XML.Сериализация.Атрибут 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
это исключение также может быть захвачено управляемый помощник по отладке (MDA) называется BindingFailure.
этот MDA полезен, если ваше приложение предназначено для поставки с предварительно построенными сборками сериализации. Мы делаем это для повышения производительности нашего приложения. Это позволяет нам убедиться, что предварительно построенные сборки сериализации правильно построены нашим процессом сборки и загружены приложением без повторного построения на летать.
Это действительно не полезно, кроме как в этом сценарии, потому что, как говорили другие плакаты, когда ошибка привязки захватывается конструктором сериализатора, сборка сериализации перестраивается во время выполнения. Так что вы можете выключить его.
Функция 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; } }
устранение ошибок компиляции с другой стороны очень сложная. Эти проблемы проявляются в 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, вызывающим систему.Отображение.Собрание.метод Load. Исключение не дает объяснения, почему сборка, которую должен был создать XmlSerializer, отсутствовала. В общем случае сборка отсутствует из-за сбоя компиляции, который может произойти из-за того, что в редких случаях атрибуты сериализации создают код, который компилятор C# не может скомпилировать.
Примечание Эта ошибка также происходит, когда XmlSerializer выполняется под учетной записью или в среде безопасности, которая не может получить доступ к временному каталогу.
источник: http://msdn.microsoft.com/en-us/library/aa302290.aspx
в свойствах проекта Visual Studio есть опция "создать сборку сериализации". Попробуйте включить его для проекта, который генерирует [содержащий сборку MyType].
пользовательский класс, чтобы serialise:
[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(); }
У меня была аналогичная проблема, и игнорирование исключений не работают для меня. Мой код вызывал конфигурацию NServiceBus
Configure.With(...).XmlSerializer()...что исправило это для меня было изменить платформу для моего проекта.
- перейти к Build\Configuration Manager...
- найдите свой проект и измените платформу (в моем случае с x86 на любой процессор)
просто как ссылка. Взяв из ответа и комментариев D-B, Я пришел с этим решением, которое близко к решению D-B. Он отлично работает во всех моих случаях, и это потокобезопасно. Я не думаю, что использование 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); } } }
ваш тип может ссылаться на другие сборки, которые не могут быть найдены ни в GAC ни в вашей локальной папке bin ==> ...
"или один из его зависимостей. Система не удается найти указанный файл"
можете ли вы привести пример типа, который вы хотите сериализовать?
Примечание: убедитесь, что ваш тип реализует Serializable.
Я получал ту же ошибку, и это было связано с типом, который я пытался десериализовать, не имея по умолчанию конструктор без параметров. Я добавил конструктор, и он начал работать.
У меня была та же проблема, пока я не использовал сторонний инструмент для создания класса из 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 { ...
Comments