C# SOAP Web Service无法反序列化响应XML复杂对象引用问题
问题根因
.NET 自带的旧版SOAP反序列化组件(System.Xml.Serialization下的SOAP编码解析器)处理SOAP Section 5多引用编码时存在顺序依赖缺陷:解析逻辑默认按XML节点从上到下的顺序加载对象、解析href引用,不会提前预加载全文档的id节点。你收到的响应中,id=2的TLagerort节点定义在引用它的TLagerortResult节点之后,解析器处理<Lagerort href="#2" />时还未加载到id=2的节点,就会抛出找不到引用元素的错误。
解决方案
- 预加载引用缓存自定义反序列化逻辑
不使用默认的反序列化直接读流,实现时先完整加载响应XML到XmlDocument,遍历全文档把所有带id属性的元素存入键为id值的字典,再自定义XmlReader重写属性读取和节点遍历逻辑,解析href属性时直接从预加载字典取对应节点,完全不受节点定义顺序影响。 - 反序列化前预处理XML响应
在拿到响应字符串后、传入序列化器前,先做格式修正:- 遍历所有带
href属性的节点,提取href指向的id值 - 找到对应id的目标节点,复制整个节点替换掉带href的空节点
- 删除Body下所有独立的带id的冗余节点、以及末尾的
<return href="#1" />根引用节点
处理后的XML没有跨节点引用,默认序列化器可以直接正常解析。
- 遍历所有带
- 替换客户端代理栈
弃用旧版「添加Web引用」生成的基于SoapHttpClientProtocol的代理类,改用WCF的svcutil或者Visual Studio的「连接服务」添加WCF Web服务引用重新生成代理,WCF的SOAP编码器原生支持乱序多引用解析,不需要额外适配就能正常处理这类响应。生成时注意选择SOAP 1.1编码模式,匹配服务端的encodingStyle配置。 - 修正代理类特性配置
你当前生成的TLagerortResult类上重复标注了两个不同命名空间下的SoapType特性,会干扰序列化器的类型识别,删掉多余的[System.Runtime.Remoting.Metadata.SoapType(XmlNamespace = "urn:LagerVerwaltungIntf")]特性,仅保留System.Xml.Serialization.SoapTypeAttribute即可;同时给Lagerort属性增加[SoapElement(IsNullable = false)]标记,明确告知序列化器该字段是引用类型,需要解析href关联。
注意:不要尝试通过修改app.config/web.config的序列化配置开关修复这个问题,系统自带的旧SOAP序列化器没有提供调整多引用解析顺序的配置项。
内容的提问来源于stack exchange,提问作者Jan
相关产品推荐
相关产品推荐

