将多个 WSDL 版本反序列化为同一个对象
我正在使用另一家公司的网络服务,他们有多个版本正在运行,每个较新的版本只添加了新的字段/对象,但更改了一些元素名称。
我希望能够使用相同代码使用任何版本。
具体来说,在一个版本中,搜索方法返回:
以及在不同版本中:
因此,由于该元素的更改,wsdl.exe 生成的代理现在无法同时使用两者。
- 最好的解决方案是让其他公司修复他们的服务以不更改元素名称,但在这种情况下这是不太可能的
- 我认为工作解决方案的最佳选择是手动发送和获取 SOAP 请求,并且修改元素名称,然后手动反序列化,到目前为止似乎可行。 ——但是需要做很多工作
- 我刚刚确认手动加载 xml(在使用 string.Replace 更改元素名称后)会将任何版本的服务反序列化为所需的对象
- 或者通过修改生成的内容来执行类似的操作代理人:
- 如果我可以在生成的代理尝试反序列化肥皂响应之前拦截并修改它
- 如果我可以在运行时修改服务的 XmlTypeAttribute
- 我还考虑过拥有一系列接口,因此每个类都会有旧
类 Data3 的接口:IData3、IData2、IData1
我认为这至少允许我向下转换。并将每个版本放入不同的命名空间中。 - 我刚刚研究了一些鸭子打字技术,它们可能可行,但似乎不太可靠。
- 还有其他方法可以从多个元素名称反序列化吗?
I'm consuming a webservice from another company, they have multiple versions running, each newer version has only added new fields/objects, BUT changes some of the element names.
I would like the ability to consume any of the versions with the same code.
Specifically In one version a search method returns:<searchReturn><SummaryData_Version1Impl /><SummaryData_Version1Impl /></searchReturn>
and in a different version: <searchReturn><SummaryData_Version2Impl /><SummaryData_Version2Impl /></searchReturn>
So right now the proxy generated by wsdl.exe cannot work with both because of that element change.
- The best solution would be to make the other company fix their service to not change the element names, but that is fairly unlikely in this situation
- I'm thinking my best bet for a working solution is to send and get the SOAP request manually, and modify the element names then deserialize manually which so far has seemed like it would work. -- But would require quite a bit of work
- I just confirmed that manually loading the xml (after changing the element name with string.Replace) will deserialize any version of the service into the needed objects
- Alternatively do a similar thing by modifying the generated proxy:
- If i could intercept and modify the soap response before the generated proxy tries to deserialize it
- If I could modify the XmlTypeAttribute of the service at runtime
- I've also thought of having a series of interfaces, so each class would have the interfaces of the older
class Data3 : IData3, IData2, IData1
Which I'm thinking would allow me to at least cast downward. And put each version into a different namespace. - There is a couple duck typing techniques I have just looked into slightly which might be able to work, but seems less reliable.
- Is there any other way to deserialize from multiple element names?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
没有办法做到这一点。不同的版本是不同的。没有办法提前知道它们有多相似。
There is no way to do this. The different versions are different. There's no way to know, ahead of time, how similar they are.
我在原来的问题中提到的选项 2 可以工作:(这不是一个完整的示例,但应该相当明显您需要修改什么才能使其在您的情况下工作,同时标记此 wiki,以便任何人都可以简化此操作将来)
此处描述的解决方案:手动发出 Soap 请求,但在处理响应后使用所有 wsdl.exe 生成的类来反序列化并保存数据。
NormalizeSummaryVersion
中,该过程的其余部分将完全相同,从而产生给定其兼容的对象。设置 WebRequest 的过程如下:(我的是一个具有基本身份验证的 https Web 服务,无法使
req.Credentials
正常工作,因此我手动添加该标头)然后将 xml 数据写入该流对于 webmethod:这是此方法的主要缺点,我还没有找到生成肥皂信封的可靠方法,对于我的服务,它似乎并不关心
xmlns 中列出的版本:ver
所以我使用这个字符串并传入SerializeObject(SearchCriteria)
注意: 下面是我的概念验证代码,我我确信它可以被清理并简化相当多的量。
这样我就可以读取来自服务的 xml 响应。接下来,我调用
NormalizeSummaryVersion
来重命名可能的节点名称差异,如果需要,还可以处理其中的任何其他节点或数据。因此,现在节点具有通用的名称和格式(额外或缺失的节点似乎并不重要,它只是忽略它们或使用此反序列化方法将它们设置为默认值)
ProcessLikeService
提取我的 XmlArray想要反序列化soapenv:Envelope
元素,并将其放入新的 XmlDocument 中,然后将其转换回字符串。因此,在
NormalizeSummaryVersion
和GetData()
内部XmlDocumentprocessedDoc
都将是这个 xml,无论 Soap 响应来自哪个版本:最后我我能够使用通用的 XmlDeserialize 方法来获取我想要的对象。 (我对所有这些的主要调用实际上返回
GetData(xmlString).searchReturn
因为通用 Deserialize 方法:
I got Option 2 that I mentioned in my original question to work: (This is not a complete example, but should be fairly obvious what you need to modify to get it to work in your situation, also marking this wiki so anyone can simplify this in the future)
Solution Described Here: Manually making the Soap Request, but using all the wsdl.exe generated classes to deserialize and hold the data, after processing the response.
NormalizeSummaryVersion
and the rest of the process will work exactly the same, resulting in the objects given its compatible.Setting up the WebRequest goes like this: (mine was a https webservice with Basic authentication, couldn't get
req.Credentials
to work correctly so I add that header manually)Then write to that stream the xml data for the webmethod: This is the main downfall of this method, I haven't found a reliable way to generate the soap envelope yet, for my service it doesn't seem to care about the version listed in
xmlns:ver
so I'm using this string withSerializeObject(SearchCriteria)
passed into itNote: Below is my proof of concept code, I'm sure it could be cleaned up and simplified a decent amount.
With that I'm able to read in the xml response from the service. Next I call
NormalizeSummaryVersion
which renames the possible node name differences, could also process any other nodes or data in this if needed.So now the nodes have a common name and format (extra or missing nodes don't seem to matter, it just ignores them or sets them to default with this method of deserialization)
ProcessLikeService
extracts the XmlArray that I want to deserialize out of thesoapenv:Envelope
elements, and puts it into a new XmlDocument, and I convert that back to a string.So after
NormalizeSummaryVersion
and inside ofGetData()
XmlDocument processedDoc
will be this xml, no matter what version the Soap Response was from:And finally I'm able to use a generic XmlDeserialize method to get the objects I want. (My main call for all of this actually returns
GetData(xmlString).searchReturn
becauseAnd the generic Deserialize method:
我现在认为最好的选择是使用 SoapExtension 并设置 SoapExtensionAttribute 以在您需要修改响应的任何方法上使用它来触发。
[ModifyResponseExtensionAttribute]
添加到任何需要修改的方法,在您的情况下,您可能需要多个 SoapExtension 类将以下类添加到您的项目:
因此,很有可能在需要时手动修改 wsdl.exe 生成的类的请求/响应。
I now think the best option is to use a SoapExtension and set a SoapExtensionAttribute to trigger using that on any methods you need to modify the response for.
[ModifyResponseExtensionAttribute]
to any methods that require the modifications, in your case you might need multiple SoapExtension classesAdd the following classes to your project:
So it is very possible to manually modify the request/responses of the wsdl.exe generated class when needed.