首页 > 解决方案 > 在 C# 中,如何使用大量精美的标记将 POCO 序列化为 XML?

问题描述

要使用 SOAP 服务,我需要以 XML 格式发送消息,如下所示:

<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>

显然,最简单的方法就是创建一个字符串并在其中插入一些变量(例如businessEventId),例如:

$"<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>"

但我宁愿实例化一些 POPO 集合,例如:

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

我需要声明哪些属性?
假设我已经有一个填充的实例,那么我需要做什么来序列化它?

--

根据@DavidBrowne 的评论,我尝试了以下不起作用的方法:

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

生成的 XML 似乎大不相同:

<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>

并且远程服务器返回错误 500。

标签: c#xmlserializationsoapnamespaces

解决方案


如果您使用的是 Visual Studio,则可以使用一个非常简单的快捷方式:将 XML 粘贴为类:

在此处输入图像描述

为您的示例 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;
                }
            }
        }

推荐阅读