XmlSerializer在构造函数处给FileNotFoundException
当我尝试序列化types时,我一直在使用的应用程序失败。
像一个声明
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)
我没有为我的class级定义任何特殊的序列化程序。
我该如何解决这个问题?
相信与否,这是正常的行为。 抛出exception但由XmlSerializer处理,所以如果你忽略它,一切都应该继续下去。
我发现这非常不合适,如果你稍微search一下,就会有很多这方面的抱怨,但从我读到的内容来看,微软并没有计划对此做任何事情。
如果closures特定exception的第一次机会exception,则可以避免在debugging过程中始终获取exceptionpopup窗口。 在Visual Studio中,进入debugging – > 例外 (或按Ctrl + Alt + E ), 公共语言运行时例外 – > System.IO – > System.IO.FileNotFoundException 。
您可以在博客文章C#XmlSerializer FileNotFoundexception (Chris Sells的工具XmlSerializerPreCompiler )中find有关其他方法的信息。
就像马丁·谢伯恩说的那样,这是正常的行为。 XmlSerializer的构造函数首先尝试查找名为[YourAssembly] .XmlSerializers.dll的程序集,该程序集应该包含生成的用于序列化types的类。 由于这样的DLL还没有生成(它们不是默认的),所以会引发FileNotFoundException。 发生这种情况时,XmlSerializer的构造函数会捕获该exception,并且该DLL由XmlSerializer的构造函数在运行时自动生成(这是通过在计算机的%temp%目录中生成C#源文件,然后使用C#编译器编译它们来完成的)。 对于相同types的XmlSerializer的其他构造将只使用已经生成的DLL。
更新:从.NET 4.5开始,除非通过设置configuration文件设置( useLegacySerializerGeneration ),否则
XmlSerializer
不再执行代码生成,也不会执行C#编译器的编译以在运行时创build序列化程序集程序集。 此更改将删除对csc.exe
的依赖关系,并提高启动性能。 来源: .NET Framework 4.5自述文件 ,第1.3.8.1节。
exception由XmlSerializer的构造函数处理。 没有必要自己做任何事情,你可以点击“继续”(F5)继续执行你的程序,一切都会好的。 如果您被停止执行程序的exception所困扰,并且popup一个exception帮助程序,您可能会closures“Just My Code”,或者在抛出时将FileNotFoundException设置为中断执行,而不是“User-未处理”。
要启用“只是我的代码”,请转到工具>>选项>>debugging>>常规>>启用只是我的代码。 要在抛出FileNotFound时closures执行中断,请转到Debug >> Exceptions >> Find >>input'FileNotFoundException >>从System.IO.FileNotFoundException中除去'Thrown'checkbox。
在Visual Studio项目属性(“生成”页面,如果我记得它是正确的)有一个选项说“生成序列化程序集”。 尝试将其打开以生成[包含MyType的程序集]的项目 。
有一个解决方法。 如果你使用
XmlSerializer lizer = XmlSerializer.FromTypes(new[] { typeof(MyType) })[0];
它应该避免这种例外。 这对我有效。
警告: 不要多次使用,否则会发生内存泄漏
如果您使用此方法为相同types的XmlSerializer
实例创build不止一次,则会像疯了一样泄漏内存!
这是因为此方法绕过了提供XmlSerializer(type)
和XmlSerializer(type, defaultNameSpace)
构造函数(所有其他构造函数也绕过caching)的内置caching。
如果您使用任何方法创build不通过这两个构造函数的XmlSerializer,则必须实现自己的caching,否则您将会失去内存。
为了避免exception,你需要做两件事情:
- 添加一个属性到序列化的类(我希望你有访问)
- 用sgen.exe生成序列化文件
将System.Xml.Serialization.XmlSerializerAssembly属性添加到您的类。 将“MyAssembly”replace为MyClass所在程序集的名称。
[Serializable] [XmlSerializerAssembly("MyAssembly.XmlSerializers")] public class MyClass { … }
使用sgen.exe实用程序生成序列化文件,并将其与类的程序集一起部署。
'sgen.exe MyAssembly.dll'将生成文件MyAssembly.XmlSerializers.dll
这两个更改将导致.net直接find程序集。 我检查了它,它与Visual Studio 2008的.NET框架3.5
我的解决scheme是直接reflection来创build序列化程序。 这绕过了导致exception的奇怪文件加载。 我把它封装在一个辅助函数中,它也负责caching序列化程序。
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; } }
此exception也可能被称为BindingFailure的托pipedebugging助手 (MDA)所困。
如果您的应用程序被devise为提供预构build序列化程序集,则此MDA非常有用。 我们这样做是为了提高应用程序的性能。 它使我们能够确保预构build的序列化程序集正在由我们的构build过程正确构build,并由应用程序加载而不需要重新构build。
除非在这种情况下,否则实际上没有用处,因为正如其他海报所说,当绑定错误被串行器构造函数困住时,序列化程序集将在运行时重新构build。 所以你通常可以把它关掉。
我遇到了这个确切的问题,无法解决任何提到的解决scheme。
然后我终于find了解决办法。 看起来序列化器不仅需要types,而且需要嵌套types。 改变这个:XmlSerializer xmlSerializer = new XmlSerializer(typeof(T)); 为此:XmlSerializer xmlSerializer = new XmlSerializer(typeof(T).GetNestedTypes()); 解决了我的问题。 没有更多的例外或什么。
函数XmlSerializer.FromTypes不会抛出exception,但会泄漏内存。 这就是为什么你需要caching这样的序列化器为每个types,以避免内存泄漏创build的每个实例。
创build你自己的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; } }
另一方面,编译错误的故障排除非常复杂。 这些问题会在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()
您可能想知道什么文件没有findexception与实例化序列化程序对象有关,但请记住:构造函数编写C#文件并尝试编译它们。 这个exception的调用堆栈提供了一些很好的信息来支持这种怀疑。 XmlSerializer尝试加载由CodeDOM调用System.Reflection.Assembly.Load方法生成的程序集时发生exception。 该exception没有提供解释为什么XmlSerializer应该创build的程序集不存在。 一般来说,程序集不存在,因为编译失败,这可能发生,因为在极less数情况下,序列化属性产生的代码,C#编译器无法编译。
注意当XmlSerializer运行在无法访问临时目录的帐户或安全环境下时,也会发生此错误。
资料来源 : http : //msdn.microsoft.com/en-us/library/aa302290.aspx
在Visual Studio项目属性中有一个选项“生成序列化程序集”。 尝试将其打开以生成[包含MyType的程序集]的项目。
要序列化的自定义类:
[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的configurationConfigure.With(...).XmlSerializer()...
对我来说固定的是改变我的项目的平台。
- 转到生成\configurationpipe理器…
- find你的项目,并改变平台(在我的情况下,从x86到任何CPU)
您的types可能会引用其他程序集,这些程序集既不能在GAC中find,也不能在您的本地bin文件夹中find==> …
“或其依赖项之一。系统找不到指定的文件”
你能举一个你想要序列化的types的例子吗?
注意:确保你的types实现了Serializable。
我得到了同样的错误,这是由于我试图反序列化没有默认的无参数构造函数的types 。 我添加了一个构造函数,并开始工作。
我有同样的问题,直到我使用第三方工具从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 { ...
就像参考一样。 从DB的答案和意见,我来到这个解决scheme是接近DB解决scheme。 它在我的所有情况下工作正常,它是线程安全的。 我不认为使用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); } } }