使用XmlDictionaryReader反序列化指定SOAP消息的技术问询
解决SOAP多节点的反序列化问题
我来帮你搞定这个SOAP响应的反序列化!你的响应里有多个<return>节点,这是SOAP返回列表数据的常见方式,下面给你两种实用的解决方案:
方案一:使用XmlSerializer自动反序列化(推荐)
首先需要定义匹配SOAP结构的实体类,重点是处理多个<return>节点——要用[XmlElement]属性而非[XmlArray],因为这里没有包裹列表的外层节点,直接是重复的<return>元素。
定义实体类
using System.Xml.Serialization; using System.Collections.Generic; // 对应SOAP的Envelope节点 [XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] public class SoapEnvelope { [XmlElement(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] public SoapBody Body { get; set; } } // 对应SOAP的Body节点 public class SoapBody { [XmlElement(ElementName = "findContractResponse", Namespace = "http://somewebsite.com/soapService")] public FindContractResponse FindContractResponse { get; set; } } // 对应findContractResponse节点 [XmlRoot(ElementName = "findContractResponse", Namespace = "http://somewebsite.com/soapService")] public class FindContractResponse { // 用[XmlElement]标记,让序列化器识别多个同名字段为列表 [XmlElement(ElementName = "return")] public List<int> ReturnValues { get; set; } // 如果是字符串就用List<string> }
补全反序列化代码
把你的代码片段补全,用XmlSerializer解析响应流:
using (Stream rs = response.GetResponseStream()) { var serializer = new XmlSerializer(typeof(SoapEnvelope)); // 反序列化得到完整的SOAP envelope对象 var envelope = (SoapEnvelope)serializer.Deserialize(rs); // 读取所有return的值 foreach (var contractId in envelope.Body.FindContractResponse.ReturnValues) { Console.WriteLine($"Contract ID: {contractId}"); // 会输出123和456 } }
方案二:手动用XDocument解析(轻量灵活)
如果不想定义实体类,也可以直接用LINQ to XML手动提取数据:
using System.Xml.Linq; using (Stream rs = response.GetResponseStream()) { var doc = XDocument.Load(rs); // 声明SOAP和服务的命名空间,必须和响应里的完全一致 XNamespace soapNs = "http://schemas.xmlsoap.org/soap/envelope/"; XNamespace serviceNs = "http://somewebsite.com/soapService"; // 链式查询找到所有return节点的值 var returnValues = doc.Descendants(soapNs + "Body") .Elements(serviceNs + "findContractResponse") .Elements("return") .Select(x => int.Parse(x.Value)) // 转成int,需要的话也可以保留字符串 .ToList(); // 处理结果 foreach (var value in returnValues) { Console.WriteLine(value); } }
关键注意事项
- 命名空间必须和SOAP响应里的完全匹配,否则会找不到目标节点
- 如果
<return>里是复杂对象,方案一的实体类可以扩展对应的属性 - 反序列化时若遇命名空间冲突,可在XmlSerializer构造时指定额外的命名空间映射
内容的提问来源于stack exchange,提问作者Teta Chronta
相关产品推荐
相关产品推荐

