扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
<portType name="nntpSoapPortType"> <operation name="getheaders" parameterOrder="newsgroup numitems"> <input message="tns:getheaders" /> <output message="tns:getheadersresponse" /> </operation> <operation name="getarticle" parameterOrder="newsgroup article"> <input message="tns:getarticle" /> <output message="tns:getarticleresponse" /> </operation> </portType> |
在进行了下面的这些微小的改变,VS.Net向导能够读取WSDL并且自动地生成一个代理。在编译了这个代理之后,它被包含在一个ASP.NET页面中。然而,当这个ASP.Net页面被执行:“ message does not have a correct SOAP root XML tag.”,这个错误被当作一个SOAP错误从Web服务中返回。为了精确地评估这个错误,代理调用被一个名为Proxy Trace的公用程序使用,以便代理生成SOAP包装。这可以通过把下列代码添加进ASP.Net页面来实现:
msNews.Proxy = new System.Net.WebProxy( "http://localhost:8080");
在察看了由.Net代理生成的SOAP包装之后,我有点奇怪为什么会返回这个错误,因为实际上一个相对的SOAP包装被生成并被发送到Web服务。即使在尝试了好几个转化成代理代码之后这个错误依然持续。代码段列表2显示了从PHP Web服务返回的完整的SOAP错误包装。
在使用VS.Net中创建的代理对象的好几个把ASP.Net页面与PHP Web服务连结的不成功的尝试之后,我决定从头开始创建SOAP包装以便执行更有效的程序调试。{起先,它看起来好像由.Net代理生成的模式域名空间可能是问题的关键,因为.Net使用2001模式规范而PHP服务使用的是1999版本的规范。
然而,我把自定义的SOAP包装改为用1999版本代替2001版本,错误依然存在。在尝试了好几个其他的小的改变之后,我决定把SOAP包装使用的域名空间前缀和正文元素从soap (由.Net代理生成)改为SOAP - ENV,因为我看见在SOAP错误信息中返回了SOAP - ENV前缀。(见代码2)这表面上看上去微不足道的改变竟解决了问题!当处理任何请求的时候,PHP服务显然需要SOAP - ENV前缀,而拒绝不包含SOAP - ENV前缀的要求。
创建一个自定义代理
既然已经了解了为什么Web服务返回一个SOAP错误,我们就可以创建一个自定义代理来生成网服务期待的SOAP包装。虽然创建一个自定义SOAP包装肯定比使用一个由VS.net或者WSDL.exe公用程序生成的SOAP包装要花更多的时间,但是这样做可以完全控制包装的内容。为了开始创建自定义代理,我创建一个名为msnewsserviceproxy的包含两个字段的新类:
public class MSNewsServiceProxy { string _uri; string _soapAction; } |
uri字段保存了Web服务的位置,而_soapAction字段保存了将要使用SOAP包装发送的SOAPAction数据头的名称。在MSNewsServiceProxy类之内,添加CreateSoapEnvelope (),SendSoapEnvelope ()和FilterResult ()这三个方法。这些方法生成SOAP包装请求,把它发送到Web服务,然后过滤返回的SOAP包装。让我们逐一的看看每个方法。注意代码在SOAP包装的根元素上添加一个SOAP - ENV域名空间前缀。Web服务显然需要这个特定的前缀,而拒绝任何不包含这个前缀的信息。因为VS.net生成的代理发送一个soap域名空间前缀(而不是SOAP - ENV),所以它的消息被拒绝。Web服务不应该需要一个特定的域名空间前缀而为此拒绝不带此前缀的消息,但是域名空间问题也是你必须注意要想使工作更好的完成,要执行一些看上去不{0>可思议的事情。
在SOAP包装被创建之后,SendSoapEnvelope ()方法(见代码段4)使用了几个System.Net和System.IO域名空间中的类来把这个包装发送到Web服务中。代码首先通过把_uri变量传送到对象构造器来创建一个HttpWebRequest对象。其次,与这个请求相关联的相应的Method,ContentType和Header都将被发送。然后一个StreamWriter对象和HttpWebRequest对象的请求流相关联,SOAP包装就被使用StreamWriter的Write ()方法写到流中。
从Web服务返回的SOAP包装被HttpWebResponse对象的SendSoapEnvelope ()方法获得。
HttpWebResponse response = (HttpWebResponse)request.GetResponse(); |
如果应答不是空值,它将被载入一个XMLTextReader,XMLTextReader被用来填充XmlDocument对象。然后从这个方法中返回XmlDocument对象。
FilterSoapEnvelope ()方法分析SOAP应答包装并把从Web服务中返回的数据装入自定义代理的“消费者”使用的XmlDocument对象:
private XmlDocument FilterSoapEnvelope( XmlDocument doc) { XmlDocument filterDoc =new XmlDocument(); XmlNode result = doc.SelectSingleNode("//results"); XmlNode resultImport = filterDoc.ImportNode(result,true); filterDoc.AppendChild(resultImport); return filterDoc; } |
虽然过滤器可以使用好几种方法执行,但是FilterSoapEnvelope ()方法依靠XPath语句可以在应答SOAP包装中得到结果元素。
微软新闻组PHP Web服务展示了允许取得新闻组新闻摘要的两种方法:getheaders ()和getmessage ()。 你可以看到如何在自定义代理类中使用这两种方法(见代码段5)。 注意每个方法中的代码传递Web服务方法名被调用到CreateSoapEnvelope ()方法和任何使用这个方法关联的参数。 在SOAP包装被发送以及应答被接受之后,FilterSoapEnvelope ()方法被调用来把返回的数据加载到一个XmlDocument对象中,同样,这个对象也是代理“消费者”使用的。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者