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