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

时间:2011-09-07 12:11:56

标签: c# .net xml-serialization sgen

我的类中有方法使用与使用默认序列化程序生成的XML结构不同的XML结构进行序列化/反序列化。这些方法为我的类型创建了一个XmlSerializer,但是有一大堆覆盖。当调用这些方法时,我猜.NET内部仍会生成序列化程序集,但我想在编译后生成此程序集,因此它不会在运行时生成。如何为此自定义序列化生成序列化程序集?如果我对该类型使用sgen.exe,它似乎只生成默认的序列化程序。

特别是我需要生成序列化程序集的原因是我的代码是从Internet Explorer进程中调用的,它在保护模式下运行。如果.net运行时尝试生成序列化程序集,则会调用csc.exe并提示用户,询问是否允许运行此进程。我不希望提示用户!所以需要在没有csc.exe的情况下完成所有序列化/反序列化。

我能想到的一个选项是捕获在运行时生成的.cs,将它放在一个单独的程序集中,然后将其包含在我的产品中。除了有点icky之外,这引发了如何在构建过程中自动生成.cs的问题......

也许还值得一提:我的自定义xml序列化也序列化了嵌套类,所以也许它们也会有自动生成的序列化器。我的自定义序列化主要是按照以下几行完成的 - 它将XmlIgnore添加到某些属性中,并从其他属性中删除XmlIgnore。其中许多属性返回需要序列化的对象,其中一些实现IXmlSerializable,一些使用默认序列化。

    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;
        }

交叉发布herehere

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

2 个答案:

答案 0 :(得分:2)

如果您使用“自定义XmlSerializer”表示您使用System.Xml.XmlSerializer自定义序列化代码(通过IXmlSerializable[XmlElement]属性和朋友),则应该查找名为的程序集序列化时MyAssembly.XmlSerializers.dll

程序集的命名非常重要,如果您不确定是否正在查找它以及查找的确切程序集名称,您可以将事件处理程序附加到AppDomain.CurrentDomain.FirstChanceException,这将为所有人启动应用程序域中的异常,包括程序集加载异常。您还可以访问AppDomain.CurrentDomain.AssemblyLoadAppDomain.CurrentDomain.AssemblyResolve事件,每次首次将程序集加载到应用程序域时都会触发事件。

另一个重要的事情是MyAssembly.dllMyAssembly.XmlSerializers.dll的版本(也许是关键;我不确定)必须匹配,它们也应该放在一起。有关详细信息,请参阅thisthis MSDN article

答案 1 :(得分:0)

(还没有足够的评论点)

您应该考虑咬住子弹并以允许您决定序列化和不序列的方式实现IXmlSerializable,而无需在运行时更改属性。定义自己的属性,构造函数要求并对其进行序列化。

也许你甚至可以解雇XML-Serialization并切换到JSon.Net,在那里需要跳过这样的环境是不太可能的。