将通用对象序列化为SOAP格式的流的扩展方法

我很难想出一个将SOAP格式化的给定对象序列化的通用扩展方法。 实际的实现看起来像这样:

Foobar.cs

[Serializable, XmlRoot("foobar"), DataContract] public class Foobar { [XmlAttribute("foo"), DataMember] public string Foo { get; set; } [XmlAttribute("bar"), DataMember] public string Bar { get; set; } public Foobar() {} } 

Lipsum.cs

 [Serializable, XmlRoot("lipsum"), XmlType("lipsum"), DataContract] public class Lipsum { private List lipsum = new List(); [XmlElement("foobar"), DataMember] public List Lipsum { get { return lipsum; } } } 

}

Extensions.cs

 public static void SerializeToSoap(this Stream target, T source) { XmlTypeMapping xmlTypeMapping = (new SoapReflectionImporter().ImportTypeMapping(typeof(T))); XmlSerializer xmlSerializer = new XmlSerializer(xmlTypeMapping); xmlSerializer.Serialize(target, source); } 

Program.cs中

 static void Main() { Lipsum lipsum = new Lipsum(); lipsum.Lipsum.Add( new Foobar() { Foo = "Lorem", Bar = "Ipsum" } ); using (MemoryStream persistence = new MemoryStream()) { persistence.SerializeToSoap(lipsum); Console.WriteLine(Encoding.Default.GetString(persistence.ToArray())); Console.WriteLine(Environment.NewLine); } } 

例外

 System.InvalidOperationException: Token StartElement in state Epilog would result in an invalid XML document. at System.Xml.XmlTextWriter.AutoComplete(Token token) at System.Xml.XmlTextWriter.WriteStartElement(String prefix, String localName, String ns) at System.Xml.Serialization.XmlSerializationWriter.WriteStartElement(String name, String ns, Object o, Boolean writePrefixed, XmlSerializerNamespaces xmlns) at System.Xml.Serialization.XmlSerializationWriter.WriteArray(String name, String ns, Object o, Type type) at System.Xml.Serialization.XmlSerializationWriter.WriteReferencedElement(String name, String ns, Object o, Type ambientType) at System.Xml.Serialization.XmlSerializationWriter.WriteReferencedElements() at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1. Write4_Lipsum(Object o) 

另一方面, XMLJSON序列化(分别使用XmlSerializerDataContractJsonSerializer )可以正常工作,具有以下预期结果:

     {"Lipsum":[{"Foo":"Lorem","Bar":"Ipsum"}]} 

任何建议都将得到真诚的感谢。 非常感谢提前。

UPDATE

正如其中一位评论者所说,有一个SoapFormatter类,但考虑到我知道它不能处理generics类型没有包含该片段。 所以无论如何这将是该场景的代码:

 public static void SerializeToSoap(this Stream target, T source) { SoapFormatter soapFormatter = new SoapFormatter(); soapFormatter.Serialize(target, source); } 

这会引发以下exception:

 Exception caught: Soap Serializer does not support serializing Generic Types : System.Collections.Generic.List`1[Foobar]. 

更新2

在Merlyn Morgan-Graham给出的带领下,我已经尝试用非generics对象提供SoapFormatter ,所以在对MemoryStream进行了一些玩杂耍后,我最终得到了这个:

 using (MemoryStream xmlStream = new MemoryStream()) { XmlSerializer xmlSerializer = new XmlSerializer(typeof(T)); xmlSerializer.Serialize(xmlStream, lipsum); using (MemoryStream soapStream = new MemoryStream()) { SoapFormatter soapFormatter = new SoapFormatter(); soapFormatter.Serialize(soapStream, Encoding.Default.GetString(xmlStream.ToArray())); Console.WriteLine(Encoding.Default.GetString(soapStream.ToArray())); Console.WriteLine(Environment.NewLine); } } 

令人惊讶的是,除了字符实体之外,还输出了一个不错的SOAP消息:

    <?xml version="1.0"?><lipsum xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">< foobar foo="Lorem" bar="Ipsum"/></lipsum>    

我(一半)通过使用另一个元素包装序列化来解决问题,ala这个论坛post: http://forums.asp.net/p/1510998/3607468.aspx ,以及这篇博文: http://sandblogaspnet.blogspot .COM / 2009/07 /系列化,在净3.html

 public static void SerializeToSoap(this Stream target, T source) { XmlTypeMapping xmlTypeMapping = (new SoapReflectionImporter().ImportTypeMapping(typeof(T))); XmlSerializer xmlSerializer = new XmlSerializer(xmlTypeMapping); using (var xmlWriter = new XmlTextWriter(target, Encoding.UTF8)) { xmlWriter.WriteStartDocument(); xmlWriter.WriteStartElement("root"); xmlSerializer.Serialize(xmlWriter, source); xmlWriter.WriteFullEndElement(); } } 

但是,该文档看起来很奇怪,并且不包含SOAP信封。 不可否认,我对SOAP知之甚少,所以也许你知道如何解决这些问题:)

编辑:

查看System.Web.Services.Protocols.SoapHttpClientProtocol中的reflection源,看起来使用了SoapReflectionImporterXmlSerializer ,但SOAP信封和正文直接在序列化代码中生成。 没有特殊帮助者暴露给用户。 因此,您可能必须使用自定义代码包装该部分消息。

从好的方面来说,代码看起来相当简单 – 只需使用正确的命名空间/属性编写正确的元素。