我在我的原始问题中提到了选项2:(这不是一个完整的例子,但应该相当明显,您需要修改以使其在您的情况下正常工作,任何人都可以在以后简化该)
解决方案描述在这里:手动使SOAP请求,但使用所有的Wsdl.exe用生成的类反序列化和保存数据,处理所述响应之后。
- 不是一个简单的解决方案,但它比使用wsdl宽松得多。exe生成的方法调用,并且任何使用生成的类的方法仍然可以正常工作
- 我相信它能够加载目标对象和源响应之间通用的任何元素,因此如果新版本只添加字段:
从较新的版本
- 负荷将所有不包括新的字段中的数据从旧版本的
- 加载,新领域将是空的
- 另一个好处是,你可以加载和从任何地方XML字符串(读从磁盘,上传到网页)到
NormalizeSummaryVersion
和其余的公关ocess将完全相同,从而导致与其兼容的对象。
设立的WebRequest是这样的:(我的是一个HTTPS Web服务使用基本身份验证,无法得到req.Credentials
到正常工作,所以我手动添加该头)
WebRequest req = WebRequest.Create(url);
req.Headers.Add("SOAPAction", soapAction);
req.ContentType = "text/xml;";
req.Method = WebRequestMethods.Http.Post;
req.Headers.Add(HttpRequestHeader.Authorization, "Basic " + basicAuthEncoded);
然后写入该为webmethod传输xml数据:这是这种方法的主要缺点,我还没有找到一种可靠的方法来生成肥皂信封,但对于我的服务,它似乎并不关心在xmlns:ver
中列出的版本我用这个字符串与SerializeObject(SearchCriteria)
传入它
//{0} is the soapAction
//{1} is the xml for that call
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ver="fake">
<soapenv:Header/>
<soapenv:Body>
<ver:{0}>
{1}
</ver:{0}>
</soapenv:Body>
</soapenv:Envelope>
注:下面是我的概念证明代码,我敢肯定,它可以被清理和简化像样的数目。
因此,我能够读取服务的xml响应。接下来,我呼叫NormalizeSummaryVersion
,它重命名可能的节点名称差异,如果需要也可以处理其中的任何其他节点或数据。
public string NormalizeSummaryVersion(string xmlString)
{
xmlString = Regex.Replace(xmlString,"SummaryData_Version2_2Impl|SummaryData_Version3_3Impl|SummaryData_Version4_4Impl",
"SummaryData_Version1_1Impl");
return xmlString;
}
所以,现在的节点有一个共同的名称和格式(额外的或丢失的节点似乎并不重要,它只是忽略它们或将它们与反序列化的这种方法使用默认值)
ProcessLikeService
提取物我想从soapenv:Envelope
元素中反序列化XmlArray,并将其放入一个新的XmlDocument中,并将其转换回字符串。
NormalizeSummaryVersion
后的GetData()
XmlDocument processedDoc
内部,从而将这个XML,不管是什么版本的SOAP响应来自:
<?xml version="1.0" encoding="utf-16"?>
<searchReturn>
<SummaryData_Version1_1Impl>
<customerFirstName>first</customerFirstName>
<customerLastName>last</customerLastName>
</SummaryData_Version1_1Impl>
</searchReturn>
最后我能使用通用XmlDeserialize方法来获取对象我想要。 (我的主要呼吁所有的这实际上返回GetData(xmlString).searchReturn
因为
[XmlRoot("searchReturn")]
public class SearchReturn
{
[XmlElement("SummaryData_Version1_1Impl", typeof(SummaryData))]
public SummaryData[] searchReturn;
}
public SearchReturn GetData(string xmlString)
{
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.LoadXml(xmlString);
System.Xml.XmlNode DataNode = doc.SelectSingleNode("//searchReturn");
System.Xml.XmlDocument processedDoc = new System.Xml.XmlDocument();
processedDoc.AppendChild(processedDoc.ImportNode(DataNode, true));
SearchReturn data = Deserialize<SearchReturn>(processedDoc);
return data;
}
和通用Deserialize方法:
public static T Deserialize<T>(XmlDocument xml)
{
XmlSerializer s = new XmlSerializer(typeof(T));
using (XmlReader reader = new XmlNodeReader(xml))
{
try
{
return (T)s.Deserialize(reader);
}
catch (Exception)
{
throw;
}
}
throw new NotSupportedException();
}