XmlSerializer不使用由sgen创建的XmlSerializers.dll

在我的Visual Studio 2010项目中,我使用以下Post-Build事件命令行来使用sgen来创建XmlSerializers.dll。

发布后事件:

"$(ProgramFiles)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\sgen.exe" /a:"$(TargetPath)" /c:/keyfile:"c:\myproject\mykey.snk" /f 

我的项目名称很强,所以使用相同的键强名“XmlSerializers.dll”。 VS在输出文件夹中创建XmlSerializers.dll。

但是,我注意到使用ProcessMonitor,.NET仍然在运行时调用CSC.exe。 我来到这篇post ,用户有类似的问题,并通过使用XmlSerializer(Type)构造函数解决。

我在我的代码中使用了相同的技术,但它仍然调用csc.exe:

 var fs = new FileStream(SettingsFilePath, FileMode.Open); try { var serializer = new XmlSerializer(typeof(AppSettings)); settings = (AppSettings)serializer.Deserialize(fs); } finally { fs.Close(); } 

我需要使用预编译的XML序列化的原因,因为性能和我有时看到Windows关闭时csc.exe错误。 我的应用程序在表单关闭时保存数据,在关闭期间,它失败,因为Windows在关闭序列期间不允许新进程启动。 我已经看到了通过预编译XML序列化来解决这个问题的建议。

有关为什么XmlSerializer不使用sgen创建的XmlSerializers.dll的任何建议?

谢谢。

Possiby问题是不同的目标平台:默认情况下sgen使用’Any CPU’(MSIL),如果包含要反序列化或序列化的类型的程序集是为x86 o x64编译的,它将不会加载.XmlSerializers.dll

更一般地说,我看一下加载序列化程序集的.NET代码 – 这里有一些代码可以重现与unit testing相同的行为:

 /// Generates an identifier for the assembly of a specified type /// Code copied from the .NET serialization classes - to emulate the same bahavior /// The type /// String identifying the type's assembly static string GenerateAssemblyId(Type type) { Module[] modules = type.Assembly.GetModules(); ArrayList list = new ArrayList(); for (int i = 0; i < modules.Length; i++) { list.Add(modules[i].ModuleVersionId.ToString()); } list.Sort(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < list.Count; i++) { sb.Append(list[i].ToString()); sb.Append(","); } return sb.ToString(); } // GenerateAssemblyId /// Verifies that the serialization assembly for the specified type can be loaded /// Code copied from the .NET serialization classes - to emulate the same behavior and tests /// The type static void AssertCanLoadXmlSerializers(Type type) { if (type == null) throw new ArgumentNullException("type"); Assembly serializerAssembly = null; // Create the name of the XML serilizers assembly from the type's one AssemblyName name = type.Assembly.GetName(true); name.Name = name.Name + ".XmlSerializers"; name.CodeBase = null; name.CultureInfo = CultureInfo.InvariantCulture; try { serializerAssembly = Assembly.Load(name); } catch (Exception e) { Assert.Fail("Unable to load XML serialization assembly for type '{0}': {1}", type.FullName, e.Message); } object[] attrs = serializerAssembly.GetCustomAttributes(typeof(XmlSerializerVersionAttribute), false); if (attrs == null || attrs.Length == 0) { Assert.Fail( "Unable to use XML serialization assembly '{1}' for type '{0}': it does not contain XmlSerializerVersionAttribute", type.FullName, serializerAssembly.FullName ); } if (attrs.Length > 1) { Assert.Fail( "Unable to use XML serialization assembly '{1}' for type '{0}': it contains multiple XmlSerializerVersionAttribute", type.FullName, serializerAssembly.FullName ); } XmlSerializerVersionAttribute assemblyInfo = (XmlSerializerVersionAttribute)attrs[0]; string assemblyId = GenerateAssemblyId(type); if (assemblyInfo.ParentAssemblyId != assemblyId) { Assert.Fail( "Unable to use XML serialization assembly '{1}' for type '{0}': it does not match assembly id '{2}'", type.FullName, serializerAssembly.FullName, assemblyId ); } } // AssertCanLoadXmlSerializers 

只需调用AssertCanLoadXmlSerializers()传递类型,而不是需要序列化/反序列化。 如果序列化程序集没有加载,您可以从错误消息中很好地了解原因。

我将它添加到我们的unit testing中,以便我可以合理地确定序列化程序集正常。

您是否尝试在生成的dll上运行ngen.exe ?

运行

 ngen.exe install myproject.XmlSerializers.dll 

将在映像缓存中安装dll的本机映像,该映像应该在运行时使用,而不是调用JIT编译器。

您确定序列化程序集已正确签名吗? 通常你需要逃避报价。 有关更多信息,请参见此处

您还可以检查ID是否匹配。 如果在构建序列化程序集后修改源程序集,则ID不再匹配,并且不会使用序列化程序集。 有关更多信息,请参见此处

如果一切正确:禁用工具 – >选项 – >调试 – >“启用我的代码”并启用调试 – >挖掘 – >公共语言运行时exception – >抛出。 然后将应用程序调试到序列化完成的位置。 将抛出第一个机会exception,说明为什么不能使用序列化程序集。