【问题标题】:In C#, how can I serialize a POCO to XML with a lot of fancy markup?在 C# 中,如何使用大量精美的标记将 POCO 序列化为 XML?
【发布时间】:2021-11-15 00:41:55
【问题描述】:

要使用 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。

【问题讨论】:

  • 这取决于您使用的序列化程序。这是 DataContractSerializer:docs.microsoft.com/en-us/dotnet/framework/wcf/samples/…
  • @DavidBrowne-Microsoft,感谢您的快速响应。假设我不在乎我使用什么序列化程序,只要它适用于 .Net 5.0 并正确完成工作。但我真正关心的是,我可以获得所有那些花哨的元素名称,包括冒号和根上的那些属性。
  • 您只需为每个元素配置命名空间。序列化程序将添加命名空间声明,它们的别名并不重要。
  • @DavidBrowne-Microsoft,再次感谢您的回复。我不是 100% 清楚你的意思......我也不会对任何与接收此消息的服务器无关的事情有任何高度的信心......即使有些事情不重要,也不能保证他们的实施是正确的或可能会被纠正。
  • 命名空间别名无关紧要是基本的 XML。只要服务器使用真正的 XML 解析器,它就可以正常工作。但是一些序列化程序可以让您控制这一点。较旧的 XmlSerializer 更复杂,但提供了更多控制。参见例如:stackoverflow.com/questions/2339782/…

标签: c# xml serialization soap namespaces


【解决方案1】:

如果您使用的是 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;
                }
            }
        }

【讨论】:

  • 布朗,为此欢呼……我会试试的。为了完整起见,一旦我创建了这些模型,是否需要使用任何特定的序列化程序才能让这些模型按预期工作?
  • 我可以使用System.Xml.XmlSerializer 来完成这项工作。干杯!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多