为自定义 XmlSerializer 生成 Xml 序列化程序集
我的类中有使用与默认序列化程序生成的 XML 结构不同的 XML 结构进行序列化/反序列化的方法。这些方法为我的类型创建一个 XmlSerializer,但具有大量重写。当调用这些方法时,我猜想.NET 在内部仍然会生成序列化程序集,但我想在编译后生成此程序集,因此它不会在运行时生成。如何为此自定义序列化生成序列化程序集?如果我将 sgen.exe 用于该类型,它似乎只生成默认序列化程序。
特别是,我需要生成序列化程序集的原因是我的代码是从 Internet Explorer 进程内调用的,该进程在保护模式下运行。如果 .net 运行时尝试生成序列化程序集,它会调用 csc.exe 并提示用户,询问是否允许运行此进程。我不希望用户收到提示!因此需要在没有 csc.exe 的情况下完成所有序列化/反序列化。
我能想到的一个选择是捕获在运行时生成的 .cs,将其放入单独的程序集中,然后将其包含在我的产品中。除了有点令人讨厌之外,这还引发了如何在构建过程中自动生成 .cs 的问题......
也许还值得一提:我的自定义 xml 序列化也序列化嵌套类,所以也许会自动生成也为它们生成了序列化器。我的自定义序列化主要是按照以下方式完成的 - 它将 XmlIgnore 添加到某些属性并从其他属性中删除 XmlIgnore。其中许多属性返回需要序列化的对象,其中一些实现 IXmlSerialized,一些使用默认序列化。
public void SerializeToCustomXml1(XmlWriter writer)
{
try
{
CustomXmlSerializer1.Serialize(writer, this);
}
catch (Exception)
{
}
}
/// <summary>
/// Static serializer so it's created just once. There's another one like this CustomXmlSerializer2 with a slightly different format again.
/// </summary>
private static XmlSerializer CustomXmlSerializer1
{
get
{
if (_customXmlSerializer == null)
{
XmlAttributes dontIgnore = new XmlAttributes();
dontIgnore.XmlIgnore = false;
XmlAttributes attributes;
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
// Include some fields in the XML that wouldn't be there otherwise.
overrides.Add(typeof (WebResource), "ID", dontIgnore);
overrides.Add(typeof (WebResource), "HasDestinationURLs", dontIgnore);
overrides.Add(typeof (Resource), "AccessDefindBy", dontIgnore);
attributes = new XmlAttributes();
attributes.XmlIgnore = false;
attributes.XmlElements.Add(new XmlElementAttribute("ActionID"));
overrides.Add(typeof(Action), "ID", attributes);
// Instead of serializing the Actions field we serialize CustomActionsXmlSerializer,
// which outputs different content in the XML
overrides.Add(typeof (WebResource), "Actions", ignore);
attributes = new XmlAttributes();
attributes.XmlIgnore = false;
attributes.XmlElements.Add(new XmlElementAttribute("Actions"));
overrides.Add(typeof (WebResource), "CustomActionsXmlSerializer", attributes);
// ... more of these overrides here ...
_customXmlSerializer1 = new XmlSerializer(typeof(WebResource), overrides);
}
return _customXmlSerializer1;
}
更新: 哦,这个答案表明这是不可能的,因为 XmlSerializer 甚至看起来都没有对于预编译的程序集(如果您使用的是 XmlOverrides)。该死。然后我想我最好的选择是生成序列化代码并将其包含在我的项目中并直接调用它而不是调用 XmlSerializer。关于如何巧妙地做到这一点有什么想法吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您所说的“自定义 XmlSerializer”意味着您使用
System.Xml.XmlSerializer
带有自定义序列化代码(通过IXmlSerialized
或[XmlElement]
属性和朋友),它应该在序列化时寻找名为MyAssembly.XmlSerializers.dll
的程序集。程序集的命名很重要,如果您不确定是否正在查找它以及正在查找的确切程序集名称是什么,您可以将事件处理程序附加到
AppDomain.CurrentDomain.FirstChanceException
它将针对应用程序中的所有异常触发域,包括程序集加载异常。您还可以连接到AppDomain.CurrentDomain.AssemblyLoad< /code>
和
AppDomain.CurrentDomain.AssemblyResolve
事件,每次程序集首次加载到应用程序域时都应触发。另一件重要的事情是
MyAssembly.dll
和MyAssembly.XmlSerializers.dll
的版本(也许是关键;我不确定)必须匹配,并且也应该放置彼此并肩。请参阅此和这篇 MSDN 文章 了解更多信息 信息。If you by "custom XmlSerializer" mean that you use
System.Xml.XmlSerializer
with custom serialization code (either throughIXmlSerializable
or[XmlElement]
attributes and friends), it should be looking for an assembly calledMyAssembly.XmlSerializers.dll
when serializing.The naming of the assembly is important, and if you're unsure whether it's being looked for and what exact assembly name is being looked up, you can just attach an event handler to
AppDomain.CurrentDomain.FirstChanceException
which will fire for all exceptions in the app domain, including assembly loading exceptions. You can also hook into theAppDomain.CurrentDomain.AssemblyLoad
andAppDomain.CurrentDomain.AssemblyResolve
events, which should fire every time an assembly is first loaded into the app domain.Another important thing is that the version (and perhaps key; I'm not sure) of
MyAssembly.dll
andMyAssembly.XmlSerializers.dll
must match and they should also be placed alongside each other. See this and this MSDN article for more information.(还没有足够的要点来评论)
您应该考虑咬紧牙关并以允许您决定序列化什么和不序列化什么的方式实现 IXmlSerialized,而无需在运行时更改属性。定义您自己的属性、构造函数要求并将它们序列化。
也许您甚至可以放弃 XML 序列化并切换到 Json.Net,因为不太可能需要跳过这样的麻烦。
(Not yet enough points to comment)
You should consider biting the bullet and implement IXmlSerializable in a manner that allows you to decide what to serialize and what not, without changing attributes at runtime. Define your own attributes, constructor requirements and serialize them.
Perhaps you could even sack XML-Serialization and switch to JSon.Net where the need to jump through such hoops is rather unlikely.