当我尝试序列化类型时,我一直在使用的应用程序失败。
像
这样的陈述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)
我没有为我的班级定义任何特殊的序列化器。
如何解决此问题?
答案 0 :(得分:364)
信不信由你,这是正常行为。抛出异常但由XmlSerializer处理,所以如果你忽略它,一切都应该继续正常。
我发现这很烦人,如果你搜索一下就会有很多关于这一点的抱怨,但是从我读过的内容来看,微软并不打算做任何事情。
如果关闭该特定异常的第一次机会异常,则可以避免在调试时始终获取异常弹出窗口。在Visual Studio中,转到 Debug - > 例外(或按 Ctrl + Alt + E ),公共语言运行时例外 - > System.IO - > System.IO.FileNotFoundException
您可以在博客文章 C# XmlSerializer FileNotFound exception (Chris Sells的工具 XmlSerializerPreCompiler )中找到有关其他方式的信息。
答案 1 :(得分:100)
更新:从.NET 4.5开始,
XmlSerializer
不再执行代码生成,也不会使用C#编译器执行编译,以便在运行时创建序列化程序程序集,除非明确强制通过设置配置文件设置(useLegacySerializerGeneration)。此更改消除了对csc.exe
的依赖性并提高了启动性能。 来源:.NET Framework 4.5 Readme,第1.3.8.1节。
异常由XmlSerializer的构造函数处理。您无需自己做任何事情,只需单击“继续”(F5)继续执行您的程序,一切都会好的。如果您对停止执行程序并弹出异常帮助程序的异常感到困扰,则可以关闭“Just My Code”,或者将FileNotFoundException设置为在抛出时执行,而不是在“User-未处理”。
要启用“仅我的代码”,请转到工具>>选项>>调试>>一般>>启用我的代码。要在抛出FileNotFound时关闭执行中断,请转到Debug>>例外>>查找>>输入'FileNotFoundException'>>从System.IO.FileNotFoundException中取消“Thrown”复选框。
答案 2 :(得分:63)
在Visual Studio项目属性(“构建”页面,如果我没记错),有一个选项说“生成序列化程序集”。尝试为生成 [包含MyType程序集] 的项目打开它。
答案 3 :(得分:58)
有一种解决方法。如果你使用
XmlSerializer lizer = XmlSerializer.FromTypes(new[] { typeof(MyType) })[0];
它应该避免这种例外。这对我有用。
警告: 请勿多次使用,否则您将遇到内存泄漏
如果您使用此方法多次为同一类型创建XmlSerializer
的实例,则会像疯了一样泄漏内存!
这是因为此方法绕过了XmlSerializer(type)
和XmlSerializer(type, defaultNameSpace)
构造函数(所有其他构造函数也绕过缓存)提供的内置缓存。
如果你使用任何方法创建一个不通过这两个构造函数的XmlSerializer,你必须实现自己的缓存,否则你会出血。
答案 4 :(得分:21)
我遇到了这个问题,无法通过提到的任何解决方案解决这个问题。
然后我终于找到了解决方案。 似乎序列化程序不仅需要类型,还需要嵌套类型。 改变这个:
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
对此:
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T).GetNestedTypes());
为我解决了这个问题。 没有更多的例外或任何事情。
答案 5 :(得分: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;
}
}
答案 6 :(得分:7)
为避免异常,您需要做两件事:
将System.Xml.Serialization.XmlSerializerAssembly属性添加到您的班级。 将'MyAssembly'替换为MyClass所在的程序集的名称。
[Serializable]
[XmlSerializerAssembly("MyAssembly.XmlSerializers")]
public class MyClass
{
…
}
使用sgen.exe实用程序生成序列化文件,并使用类的程序集部署它。
'sgen.exe MyAssembly.dll'将生成文件MyAssembly.XmlSerializers.dll
这两个更改将导致.net直接查找程序集。 我检查了它,它适用于使用Visual Studio 2008的.NET framework 3.5
答案 7 :(得分:6)
此异常也可以被称为BindingFailure的managed debugging assistant(MDA)捕获。
如果您的应用程序旨在提供预构建的序列化程序集,则此MDA非常有用。我们这样做是为了提高应用程序的性能。它允许我们确保构建过程正确构建预构建的序列化程序集,并由应用程序加载而无需动态重新构建。
除了在这种情况下,它确实没用,因为正如其他海报所说,当Serializer构造函数捕获绑定错误时,序列化程序集在运行时重新构建。所以你通常可以把它关掉。
答案 8 :(得分: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;
}
}
答案 9 :(得分: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
答案 10 :(得分:2)
在Visual Studio项目属性中,有一个选项说“生成序列化程序集”。尝试为生成[包含MyType程序集]的项目启用它。
答案 11 :(得分: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();
}
答案 12 :(得分:1)
仅供参考。从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);
}
}
}
答案 13 :(得分:1)
我遇到了类似的问题,忽略异常并不适用于我。我的代码调用了NServiceBus的配置Configure.With(...).XmlSerializer()...
为我修复的是改变我项目的平台。
答案 14 :(得分:0)
我的一个.Net Standard dll中存在类似的问题。
我使用了Microsoft.XmlSerializer.Generator nuget,它可以在.Net Core和.Net Standard上预生成XmlSerializer。
答案 15 :(得分: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;
}
答案 16 :(得分: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
{
...
答案 17 :(得分:0)
我得到了同样的错误,这是由于我试图反序列化没有默认无参数构造函数的类型。我添加了一个构造函数,它开始工作了。
答案 18 :(得分:0)
您的类型可能会引用在GAC或本地bin文件夹中找不到的其他程序集==&gt; ......
“或其中一个依赖项。系统 找不到指定的文件“
您能举例说明要序列化的类型吗?
注意:确保您的类型实现Serializable。