Extension method for serializing shared objects as a stream in SOAP format

I find it difficult to find a general extension method that serializes this object as SOAP . The actual implementation looks something like this:

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<Foobar> lipsum = new List<Foobar>(); [XmlElement("foobar"), DataMember] public List<Foobar> Lipsum { get { return lipsum; } } } 

}

Extensions.cs

 public static void SerializeToSoap<T>(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>(lipsum); Console.WriteLine(Encoding.Default.GetString(persistence.ToArray())); Console.WriteLine(Environment.NewLine); } } 

Exception

 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) 

On the other hand, serializing XML and JSON (using XmlSerializer and DataContractJsonSerializer respectively) works fine with the following expected results:

 <?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> {"Lipsum":[{"Foo":"Lorem","Bar":"Ipsum"}]} 

Any advice would be truly appreciated. Thank you very much in advance.

UPDATE

As one commenter noted, there is a SoapFormatter class, but given that I knew that it could not deal with common types, this fragment did not include. One way or another, this will be the code for this scenario:

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

This throws the following exception:

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

UPDATE 2

Following Merlin Morgan-Graham's directions, I tried to feed the SoapFormatter non-universal object, so after a bit of juggling with MemoryStream I ended up with this:

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

Surprisingly, character objects aside, produce a decent SOAP message:

 <SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <SOAP-ENC:string id="ref-1"> &#60;?xml version=&#34;1.0&#34;?&#62;&#60;lipsum xmlns:xsi=&#34;http://www.w3.org/2001/XMLSchema-instance&#34; xmlns:xsd=&#34;http://www.w3.org/2001/XMLSchema&#34;&#62;&#60; foobar foo=&#34;Lorem&#34; bar=&#34;Ipsum&#34;/&#62;&#60;/lipsum&#62; </SOAP-ENC:string> </SOAP-ENV:Body> </SOAP-ENV:Envelope> 
+6
source share
1 answer

I (half) solved the problem by wrapping serialization with another element, ala this is a forum post: http://forums.asp.net/p/1510998/3607468.aspx , and this blog post: http: //sandblogaspnet.blogspot. com / 2009/07 / serialization-in-net-3.html

 public static void SerializeToSoap<T>(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(); } } 

The document looks really strange and does not contain a SOAP envelope. Admittedly, I know very little about SOAP, so maybe you know how to solve these problems :)

Edit:

Looking at the reflected source in System.Web.Services.Protocols.SoapHttpClientProtocol , it looks like SoapReflectionImporter and XmlSerializer , but the SOAP wrapper and body are generated directly inside the serialization code. Users are not provided with special assistants. Therefore, you probably have to wrap this part of the message with special code.

On the plus side, the code looks pretty simple - just write the correct elements with the appropriate namespaces / attributes.

+4
source

Source: https://habr.com/ru/post/890849/


All Articles