为自定义 XmlSerializer 生成 Xml 序列化程序集

问题描述 投票:0回答:3

我的类中有使用与默认序列化程序生成的 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;
        }

交叉发布这里这里

更新: 哦,这个答案表明这是不可能的,因为如果您使用 XmlOverrides,XmlSerializer 甚至不会查找预编译的程序集。该死。然后我想我最好的选择是生成序列化代码并将其包含在我的项目中并直接调用它而不是调用 XmlSerializer。关于如何巧妙地做到这一点有什么想法吗?

c# .net xml-serialization sgen
3个回答
2
投票

如果您所说的“自定义 XmlSerializer”意味着您将

System.Xml.XmlSerializer
与自定义序列化代码一起使用(通过
IXmlSerializable
[XmlElement]
属性和朋友),则它应该寻找名为
MyAssembly.XmlSerializers.dll 的程序集
序列化时。

程序集的命名很重要,如果您不确定是否正在查找它以及正在查找的确切程序集名称,您可以将一个事件处理程序附加到

AppDomain.CurrentDomain.FirstChanceException
,它将触发所有异常应用程序域,包括程序集加载异常。您还可以挂钩
AppDomain.CurrentDomain.AssemblyLoad
AppDomain.CurrentDomain.AssemblyResolve
事件,每次程序集首次加载到应用程序域时都会触发这些事件。

另一个重要的事情是

MyAssembly.dll
MyAssembly.XmlSerializers.dll
的版本(也许是关键;我不确定)必须匹配,并且它们也应该并排放置。请参阅此 MSDN 文章了解更多信息。


1
投票

(还没有足够的积分来评论)

您应该考虑咬紧牙关并以允许您决定序列化什么和不序列化什么的方式实现 IXmlSerialized,而无需在运行时更改属性。定义您自己的属性、构造函数要求并将它们序列化。

也许您甚至可以放弃 XML 序列化并切换到 Json.Net,因为不太可能需要跳过这样的麻烦。


0
投票

https://learn.microsoft.com/en-us/dotnet/core/additional-tools/xml-serializer-generator

希望它对每个在 .Net Core 应用程序中遇到此问题并使用反射的人有所帮助

© www.soinside.com 2019 - 2024. All rights reserved.