Home > Net >  In C#, how can I serialize a POCO to XML with a lot of fancy markup?
In C#, how can I serialize a POCO to XML with a lot of fancy markup?

Time:09-22

To consume a SOAP service, I need to send messages in XML which looks like:

<soap:Envelope 
    xmlns:soap="http://www.w3.org/2003/05/soap-envelope" 
    xmlns:bus="http://ws.praxedo.com/v6/businessEvent">
    
    <soap:Header/>
    <soap:Body>
        <bus:listAttachments>
                <businessEventId>00044</businessEventId>
        </bus:listAttachments>
    </soap:Body>
</soap:Envelope>

Obviously, the easy way to do this would just be to create a string and interpolate some variable (e.g. businessEventId) into the midst of it, like:

$"<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\""
  " xmlns:bus=\"http://ws.praxedo.com/v6/businessEvent\">"
  "<soap:Header/><soap:Body>"
  "<bus:listAttachments><businessEventId>{businessEventId}</businessEventId>"
  "</bus:listAttachments></soap:Body></soap:Envelope>"

But I'd rather instantiate some collection of POPO, like:

public class Envelope {
   public Header Header {get; init;}
   public Body Body {get; init;}
}

public class Header {
}

public class Body {
   public ListAttachments Attachments {get; init;}
}

public class ListAttachments {
   public string BusinessEventId {get; init;}
}

What Attributes do I need to declare?
And what would I then need to do to serialize this, assuming I have a populated instance already?

--

As per @DavidBrowne's comment, I've tried the following which does NOT work:

        private string CreateBody(string businessEventId)
        {
            BusinessEventAttachmentListRequestEnvelope envelope = BusinessEventAttachmentListRequestEnvelope.From(businessEventId);

            MemoryStream memorystream = new();
            DataContractSerializer serializer = new(typeof(BusinessEventAttachmentListRequestEnvelope));
            serializer.WriteObject(memorystream, envelope);

            memorystream.Seek(0, SeekOrigin.Begin);

            using StreamReader streamReader = new(memorystream);
            return streamReader.ReadToEnd();
        }

    [DataContract(Name = "Envelope", Namespace = "http://www.w3.org/2003/05/soap-envelope")]
    public class BusinessEventAttachmentListRequestEnvelope
    {
        [DataMember]
        EmptySoapHeader Header = new();

        [DataMember]
        BusinessEventAttachmentListRequestBody Body { get; init; }

        public static BusinessEventAttachmentListRequestEnvelope From(string businessEventId) =>
            new()
            {
                Body = new()
                {
                    Request = new()
                    {
                        BusinessEventId = businessEventId
                    }
                }
            };
    }

    [DataContract(Name = "Header", Namespace = "http://www.w3.org/2003/05/soap-envelope")]
    public class EmptySoapHeader
    {
    }

    [DataContract(Name = "Body", Namespace = "http://www.w3.org/2003/05/soap-envelope")]
    public class BusinessEventAttachmentListRequestBody
    {
        [DataMember(Name = "listAttachments")]
        public BusinessEventAttachmentListRequest Request { get; init; }
    }

    [DataContract(Name = "listAttachments", Namespace = "http://ws.praxedo.com/v6/businessEvent")]
    public class BusinessEventAttachmentListRequest
    {
        [DataMember(Name = "businessEventId")]
        public string BusinessEventId { get; init; }
    }

The resulting XML seems substantially different:

<Envelope xmlns=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">
    <Body>
        <listAttachments xmlns:a=\"http://ws.praxedo.com/v6/businessEvent\">
            <a:businessEventId>00044</a:businessEventId>
        </listAttachments>
    </Body>
    <Header/>
</Envelope>

And the remote server returns error 500.

CodePudding user response:

If you're using Visual Studio there's a really easy shortcut you can use: Paste XML as Classes:

enter image description here

Which creates for your sample XML:

// NOTE: Generated code may require at least .NET Framework 4.5 or .NET Core/Standard 2.0.
        /// <remarks/>
        [System.SerializableAttribute()]
        [System.ComponentModel.DesignerCategoryAttribute("code")]
        [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2003/05/soap-envelope")]
        [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.w3.org/2003/05/soap-envelope", IsNullable = false)]
        public partial class Envelope
        {

            private object headerField;

            private EnvelopeBody bodyField;

            /// <remarks/>
            public object Header
            {
                get
                {
                    return this.headerField;
                }
                set
                {
                    this.headerField = value;
                }
            }

            /// <remarks/>
            public EnvelopeBody Body
            {
                get
                {
                    return this.bodyField;
                }
                set
                {
                    this.bodyField = value;
                }
            }
        }

        /// <remarks/>
        [System.SerializableAttribute()]
        [System.ComponentModel.DesignerCategoryAttribute("code")]
        [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2003/05/soap-envelope")]
        public partial class EnvelopeBody
        {

            private listAttachments listAttachmentsField;

            /// <remarks/>
            [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://ws.praxedo.com/v6/businessEvent")]
            public listAttachments listAttachments
            {
                get
                {
                    return this.listAttachmentsField;
                }
                set
                {
                    this.listAttachmentsField = value;
                }
            }
        }

        /// <remarks/>
        [System.SerializableAttribute()]
        [System.ComponentModel.DesignerCategoryAttribute("code")]
        [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://ws.praxedo.com/v6/businessEvent")]
        [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://ws.praxedo.com/v6/businessEvent", IsNullable = false)]
        public partial class listAttachments
        {

            private byte businessEventIdField;

            /// <remarks/>
            [System.Xml.Serialization.XmlElementAttribute(Namespace = "")]
            public byte businessEventId
            {
                get
                {
                    return this.businessEventIdField;
                }
                set
                {
                    this.businessEventIdField = value;
                }
            }
        }
  • Related