Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XmlSerializer Serialize empty variable to use both tags?

I want to be able to load a serialized xml class to a Soap Envelope. I am starting so I am not filling the innards so it appears like:

<Envelope    
xmlns="http://schemas.xmlsoap.org/soap/envelope/" /> 

I want it to appear like:

<Envelope    
xmlns="http://schemas.xmlsoap.org/soap/envelope/" ></Envelope>`


The class I wrote is this:

[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://schemas.xmlsoap.org/soap/envelope/",ElementName="Envelope", IsNullable = true)]
public class TestXmlEnvelope
{
  [System.Xml.Serialization.XmlElement(ElementName="Body", Namespace="http://schemas.xmlsoap.org/soap/envelope/")]
  public System.Collections.ArrayList Body = new System.Collections.ArrayList();
} //class TestXmlEnvelope`

I am using this as an example since other people might want it in an individual element. I am sure this must be simple but sadly I don't know the right keyword for this.

As always thanks for your help.

[Edit] The error comes when I try to use this instruction

System.Xml.Serialization.XmlSerializer xmlout = new System.Xml.Serialization.XmlSerializer(typeof(TestXmlEnvelope));
System.IO.MemoryStream memOut = new System.IO.MemoryStream();
xmlout.Serialize(memOut, envelope, namespc);
Microsoft.Web.Services.SoapEnvelope soapEnv = new Microsoft.Web.Services.SoapEnvelope();
soapEnv.Load(memOut);

It gives me error "Root Element not found".

[Edit] I fixed the error the problem was that after I serialized the object I didn't set the memOut.Position = 0. Still I hope this question helps other people that may want to do this.

like image 762
ThorDivDev Avatar asked Oct 31 '08 20:10

ThorDivDev


2 Answers

The main issue here is that the XmlSerializer calls WriteEndElement() on the XmlWriter when it would write an end tag. This, however, generates the shorthand <tag/> form when there is no content. The WriteFullEndElement() writes the end tag separately.

You can inject your own XmlTextWriter into the middle that the serializer would then use to exhibit that functionality.

Given that serializer is the appropriate XmlSerializer, try this:

public class XmlTextWriterFull : XmlTextWriter
{
    public XmlTextWriterFull(TextWriter sink) : base(sink) { }

    public override void WriteEndElement()
    {
        base.WriteFullEndElement();
    }
}

...

var writer = new XmlTextWriterFull(innerwriter);
serializer.Serialize(writer, obj);

[Edit] for the case of your added code, add facade constructors for:

public XmlTextWriterFull(Stream stream, Encoding enc) : base(stream, enc) { }
public XmlTextWriterFull(String str, Encoding enc) : base(str, enc) { }

Then, use the memory stream as your inner stream in the constructor as before:

System.IO.MemoryStream memOut = new System.IO.MemoryStream();
XmlTextWriterFull writer = new XmlTextWriterFull(memOut, Encoding.UTF8Encoding); //Or the encoding of your choice
xmlout.Serialize(writer, envelope, namespc);
like image 61
Marcus Griep Avatar answered Sep 27 '22 20:09

Marcus Griep


Note for the record: The OP was using the ***Microsoft.***Web.Services.SoapEnvelope class, which is part of the extremely obsolete WSE 1.0 product. This class derived from the XmlDocument class, so it's possible that the same issues would have been seen with XmlDocument.

Under no circumstances should WSE be used for any new development, and if it is already in use, the code should be migrated as soon as possible. WCF or ASP.NET Web API are the only technologies that should be used for .NET web services going forward.

like image 31
John Saunders Avatar answered Sep 27 '22 22:09

John Saunders