在 C# 中,如何使用大量精美的标记将 POCO 序列化为 XML?

Posted

技术标签:

【中文标题】在 C# 中,如何使用大量精美的标记将 POCO 序列化为 XML?【英文标题】:In C#, how can I serialize a POCO to XML with a lot of fancy markup? 【发布时间】: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 更复杂,但提供了更多控制。参见例如:***.com/questions/2339782/… 【参考方案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 来完成这项工作。干杯!

以上是关于在 C# 中,如何使用大量精美的标记将 POCO 序列化为 XML?的主要内容,如果未能解决你的问题,请参考以下文章

使用 JsonConvert.DeserializeObject 将 Json 反序列化为 C# POCO 类

DDD:尝试使用 C# 对与 Poco、Repository、DTO 和 DAO 相关的代码排序和过滤?

如何在 POCO C++ 库中正确使用 OpenSSL

POCO 生成工具

替代手动 ADO.NET POCO 映射?

C# XslCompiledTransform - 以 POCO 形式而不是 Html 输出