具有嵌套类的类将引发InvalidOperationException:状态Epilog中的令牌StartElement将导致无效的XML文档

问题描述

我正在尝试使用System.Xml.Serialization.XmlSerializer对具有SOAP请求的单个属性的简单类进行序列化,该方法可以正常工作,但是一旦我向类中添加了另一个属性并且该属性类型是另一个类,执行XmlSerializer.Serialize(StringWriter,myclass)时收到此错误消息:

InvalidOperationException: Token StartElement in state Epilog would result in an invalid XML document.

这两个类很简单:

[XmlRoot(Namespace = "http://example.org/",ElementName = "Foo")]
public class Foo
{
    public string Id { get; set; }
    public Bar Bar { get; set; }
}

public class Bar
{
    public string Id { get; set; }
}

这是我执行序列化的方式:

var foo = new Foo(Id = "foo-id",Bar = new Bar { Id = "bar-id" });
var soapReflectionImporter = new SoapReflectionImporter("http://example.org");
var xmlTypeMapping = soapReflectionImporter.ImportTypeMapping(typeof(Foo));
var serializer = new XmlSerializer(xmlTypeMapping);
using (var writer = new StringWriter())
{
    serializer.Serialize(writer,foo);
}

如果我从Bar删除Foo属性,一切都会按预期进行。我已经浏览了thisthis,但没有解决问题。我也不能简单地使用类型参数调用XmlSerializer的构造函数,因为我需要XmlTypeMapping来处理SOAP请求。有人可以指出问题出在哪里,或者我是否缺少其他配置?

解决方法

输出XML需要一个根元素。结合使用XmlWriter和XmlWriterSettings可以提供帮助,如下所示。

[XmlRoot(Namespace = "http://example.org/",ElementName = "Foo")]
public class Foo
{
    public string Id { get; set; }
    public Bar Bar { get; set; }
}

    
public class Bar
{
    public string Id { get; set; }
}

public class Program
{
    static void Main(string[] args)
    {
        var foo = new Foo() { Id = "foo-id",Bar = new Bar { Id = "bar-id" } };
        var soapReflectionImporter = new SoapReflectionImporter("http://example.org");
        var xmlTypeMapping = soapReflectionImporter.ImportTypeMapping(typeof(Foo));
        var serializer = new XmlSerializer(xmlTypeMapping);
        //using (var writer = new StringWriter())
        //{
        //    serializer.Serialize(writer,foo);
        //}

        Stream st = new MemoryStream();
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.Indent = true;
        settings.WriteEndDocumentOnClose = true;
        XmlWriter writer = XmlWriter.Create(st,settings);

        writer.WriteStartElement("base");
        serializer.Serialize(writer,foo);
        writer.Close();  //will write the final closing tag

        st.Position = 0;
        StreamReader sr = new StreamReader(st);
        string data = sr.ReadToEnd();
    }
}