2008-11-01 123 views
9

(如果有的话在这里需要澄清/详细请让我知道。)如何获得访问SOAP响应

我有一个应用程序(C#,2 *框架)与第三方Web服务接口使用SOAP。我使用thinktecture的WSCF加载项来提供WSDL来创建客户端实现。由于我无法控制的原因,SOAP消息交换使用WSE2.0进行安全性(必须修改thinctecture实现以包含WSE2.0参考)。除了'普通'数据包之外,我还将以前调用中存储的X509证书和二进制安全令牌附加到不同的Web服务。我们正在使用某种SSL加密 - 我不知道细节。

所有必需的序列化/反序列化都包含在Web服务客户端中 - 意味着在调用客户端后返回给我的控制权时,SOAP响应中包含的整个XML字符串对我来说不可用 - 仅仅是反序列化的组件。不要误解我的意思 - 我认为这很好,因为这意味着我不必亲自去做。

但是,为了让我有一些值得存储/存档我将不得不重新序列化的根元素中的数据。这看起来像是浪费资源,因为我的结果是在SOAP响应中。

现在对于我的问题: 如何访问“清晰”的SOAP响应版本,以便我不必重新序列化存储/归档的所有内容?

编辑 - 我的应用程序作为网络服务的“无形的” Windows应用程序 - 由WebsphereMQ客户端触发监控触发。我不认为ASP.NET解决方案将适用。

编辑 - 由于到目前为止的共识是无论我的应用程序是否为ASP.NET,我都会给CodeMelt的(并延伸Chris的)解决方案一枪。

回答

8

您可以从现有的WSE2.0框架使用的SoapExtension拦截来自服务器的响应。

public class MyClientSOAPExtension : SoapExtension 
{ 

    Stream oldStream; 
    Stream newStream; 

    // Save the Stream representing the SOAP request or SOAP response into 
    // a local memory buffer. 
    public override Stream ChainStream(Stream stream) 
    { 
      oldStream = stream; 
      newStream = new MemoryStream(); 
      return newStream; 
    } 

    public override void ProcessMessage(SoapMessage message) 
    { 
     switch (message.Stage) 
     { 
      case SoapMessageStage.BeforeDeserialize: 
       // before the XML deserialized into object. 
       break; 
      case SoapMessageStage.AfterDeserialize: 
       break;   
      case SoapMessageStage.BeforeSerialize: 
       break; 
      case SoapMessageStage.AfterSerialize: 
       break;    
      default: 
       throw new Exception("Invalid stage..."); 
     }  
    } 
} 

在SoapMessageStage.BeforeDeserialize的阶段, 你可以阅读你oldstream想要的预期数据(例如使用的XmlReader)。 然后存储预期的数据的地方为自己使用,你也需要 着旧的数据流的为方通网络服务后一阶段使用的数据,例如将XML反序列化为对象。

The sample of logging all the traffic for the web service from MSDN

+0

好吧 - 这是克里斯上面发布的链接。这是“ASP.NET”让我很担心。由于迄今为止的共识是,无论我的应用程序是否为ASP.NET,我都会给它一个镜头。 – 2008-11-02 01:16:09

0

MSDN Library包含示例代码,用于获取可用于存档的请求和响应的XML。显然你必须做一些改变,因为这个例子将数据存储在一个文本文件中,但它不是太复杂。

+0

对不起 - 我应该包括,我不使用ASP.NET - 它在编辑 – 2008-11-01 23:30:29

6

这里是http://footballpool.dataaccess.eu/data/info.wso?WSDL

基本上是一个例子,你可以使用Visual Studio的Web引用设置时,必须在Web服务调用链插入的XmlReader spyer将重建原始的XML。

我相信这种方式是有点简单,使用SoapExtensions。

解溶液通过http://orbinary.com/blog/2010/01/getting-the-raw-soap-xml-sent-via-soaphttpclientprotocol/

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Net; 
using System.IO; 
using System.Reflection; 
using System.Xml; 


namespace ConsoleApplication1 { 

    public class XmlReaderSpy : XmlReader { 
     XmlReader _me; 
     public XmlReaderSpy(XmlReader parent) { 
      _me = parent; 
     } 

     /// <summary> 
     /// Extracted XML. 
     /// </summary> 
     public string Xml; 

     #region Abstract method that must be implemented 
     public override XmlNodeType NodeType { 
      get { 

       return _me.NodeType; 
      } 
     } 

     public override string LocalName { 
      get { 
       return _me.LocalName; 
      } 
     } 

     public override string NamespaceURI { 
      get { 
       return _me.NamespaceURI; 
      } 
     } 

     public override string Prefix { 
      get { 
       return _me.Prefix; 
      } 
     } 

     public override bool HasValue { 
      get { return _me.HasValue; } 
     } 

     public override string Value { 
      get { return _me.Value; } 
     } 

     public override int Depth { 
      get { return _me.Depth; } 
     } 

     public override string BaseURI { 
      get { return _me.BaseURI; } 
     } 

     public override bool IsEmptyElement { 
      get { return _me.IsEmptyElement; } 
     } 

     public override int AttributeCount { 
      get { return _me.AttributeCount; } 
     } 

     public override string GetAttribute(int i) { 
      return _me.GetAttribute(i); 
     } 

     public override string GetAttribute(string name) { 
      return _me.GetAttribute(name); 
     } 

     public override string GetAttribute(string name, string namespaceURI) { 
      return _me.GetAttribute(name, namespaceURI); 
     } 

     public override void MoveToAttribute(int i) { 
      _me.MoveToAttribute(i); 
     } 

     public override bool MoveToAttribute(string name) { 
      return _me.MoveToAttribute(name); 
     } 

     public override bool MoveToAttribute(string name, string ns) { 
      return _me.MoveToAttribute(name, ns); 
     } 

     public override bool MoveToFirstAttribute() { 
      return _me.MoveToFirstAttribute(); 
     } 

     public override bool MoveToNextAttribute() { 
      return _me.MoveToNextAttribute(); 
     } 

     public override bool MoveToElement() { 
      return _me.MoveToElement(); 
     } 

     public override bool ReadAttributeValue() { 
      return _me.ReadAttributeValue(); 
     } 

     public override bool Read() { 
      bool res = _me.Read(); 

      Xml += StringView(); 


      return res; 
     } 

     public override bool EOF { 
      get { return _me.EOF; } 
     } 

     public override void Close() { 
      _me.Close(); 
     } 

     public override ReadState ReadState { 
      get { return _me.ReadState; } 
     } 

     public override XmlNameTable NameTable { 
      get { return _me.NameTable; } 
     } 

     public override string LookupNamespace(string prefix) { 
      return _me.LookupNamespace(prefix); 
     } 

     public override void ResolveEntity() { 
      _me.ResolveEntity(); 
     } 

     #endregion 


     protected string StringView() { 
      string result = ""; 

      if (_me.NodeType == XmlNodeType.Element) { 
       result = "<" + _me.Name; 

       if (_me.HasAttributes) { 
        _me.MoveToFirstAttribute(); 
        do { 
         result += " " + _me.Name + "=\"" + _me.Value + "\""; 
        } while (_me.MoveToNextAttribute()); 

        //Let's put cursor back to Element to avoid messing up reader state. 
        _me.MoveToElement(); 
       } 

       if (_me.IsEmptyElement) { 
        result += "/"; 
       } 

       result += ">"; 
      } 

      if (_me.NodeType == XmlNodeType.EndElement) { 
       result = "</" + _me.Name + ">"; 
      } 

      if (_me.NodeType == XmlNodeType.Text || _me.NodeType == XmlNodeType.Whitespace) { 
       result = _me.Value; 
      } 



      if (_me.NodeType == XmlNodeType.XmlDeclaration) { 
       result = "<?" + _me.Name + " " + _me.Value + "?>"; 
      } 

      return result; 

     } 
    } 

    public class MyInfo : ConsoleApplication1.eu.dataaccess.footballpool.Info {    

     protected XmlReaderSpy _xmlReaderSpy; 

     public string Xml { 
      get { 
       if (_xmlReaderSpy != null) { 
        return _xmlReaderSpy.Xml; 
       } 
       else { 
        return ""; 
       } 
      } 
     } 


     protected override XmlReader GetReaderForMessage(System.Web.Services.Protocols.SoapClientMessage message, int bufferSize) {   
      XmlReader rdr = base.GetReaderForMessage(message, bufferSize); 
      _xmlReaderSpy = new XmlReaderSpy((XmlReader)rdr); 
      return _xmlReaderSpy; 
     } 

    } 

    class Program { 
     static void Main(string[] args) { 

      MyInfo info = new MyInfo(); 
      string[] rest = info.Cities(); 

      System.Console.WriteLine("RAW Soap XML response :\n"+info.Xml); 
      System.Console.ReadLine(); 
     } 
    } 
} 
3

通过jfburdet启发启发,我想看看它是否是可以直接拦截在流/字节电平,而不是重建XML。它是!见下面的代码:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Text; 
using System.Web.Services.Protocols; 
using System.Xml; 

using Test.MyWebReference; 

namespace Test { 
    /// <summary> 
    /// Adds the ability to retrieve the SOAP request/response. 
    /// </summary> 
    public class ServiceSpy : OriginalService { 
     private StreamSpy writerStreamSpy; 
     private XmlTextWriter xmlWriter; 

     private StreamSpy readerStreamSpy; 
     private XmlTextReader xmlReader; 

     public MemoryStream WriterStream { 
      get { return writerStreamSpy == null ? null : writerStreamSpy.ClonedStream; } 
     } 

     public XmlTextWriter XmlWriter { 
      get { return xmlWriter; } 
     } 

     public MemoryStream ReaderStream { 
      get { return readerStreamSpy == null ? null : readerStreamSpy.ClonedStream; } 
     } 

     public XmlTextReader XmlReader { 
      get { return xmlReader; } 
     } 

     protected override void Dispose(bool disposing) { 
      base.Dispose(disposing); 
      DisposeWriterStreamSpy(); 
      DisposeReaderStreamSpy(); 
     } 

     protected override XmlWriter GetWriterForMessage(SoapClientMessage message, int bufferSize) { 
      // Dispose previous writer stream spy. 
      DisposeWriterStreamSpy(); 

      writerStreamSpy = new StreamSpy(message.Stream); 
      // XML should always support UTF8. 
      xmlWriter = new XmlTextWriter(writerStreamSpy, Encoding.UTF8); 

      return xmlWriter; 
     } 

     protected override XmlReader GetReaderForMessage(SoapClientMessage message, int bufferSize) { 
      // Dispose previous reader stream spy. 
      DisposeReaderStreamSpy(); 

      readerStreamSpy = new StreamSpy(message.Stream); 
      xmlReader = new XmlTextReader(readerStreamSpy); 

      return xmlReader; 
     } 

     private void DisposeWriterStreamSpy() { 
      if (writerStreamSpy != null) { 
       writerStreamSpy.Dispose(); 
       writerStreamSpy.ClonedStream.Dispose(); 
       writerStreamSpy = null; 
      } 
     } 

     private void DisposeReaderStreamSpy() { 
      if (readerStreamSpy != null) { 
       readerStreamSpy.Dispose(); 
       readerStreamSpy.ClonedStream.Dispose(); 
       readerStreamSpy = null; 
      } 
     } 

     /// <summary> 
     /// Wrapper class to clone read/write bytes. 
     /// </summary> 
     public class StreamSpy : Stream { 
      private Stream wrappedStream; 
      private long startPosition; 
      private MemoryStream clonedStream = new MemoryStream(); 

      public StreamSpy(Stream wrappedStream) { 
       this.wrappedStream = wrappedStream; 
       startPosition = wrappedStream.Position; 
      } 

      public MemoryStream ClonedStream { 
       get { return clonedStream; } 
      } 

      public override bool CanRead { 
       get { return wrappedStream.CanRead; } 
      } 

      public override bool CanSeek { 
       get { return wrappedStream.CanSeek; } 
      } 

      public override bool CanWrite { 
       get { return wrappedStream.CanWrite; } 
      } 

      public override void Flush() { 
       wrappedStream.Flush(); 
      } 

      public override long Length { 
       get { return wrappedStream.Length; } 
      } 

      public override long Position { 
       get { return wrappedStream.Position; } 
       set { wrappedStream.Position = value; } 
      } 

      public override int Read(byte[] buffer, int offset, int count) { 
       long relativeOffset = wrappedStream.Position - startPosition; 
       int result = wrappedStream.Read(buffer, offset, count); 
       if (clonedStream.Position != relativeOffset) { 
        clonedStream.Position = relativeOffset; 
       } 
       clonedStream.Write(buffer, offset, result); 
       return result; 
      } 

      public override long Seek(long offset, SeekOrigin origin) { 
       return wrappedStream.Seek(offset, origin); 
      } 

      public override void SetLength(long value) { 
       wrappedStream.SetLength(value); 
      } 

      public override void Write(byte[] buffer, int offset, int count) { 
       long relativeOffset = wrappedStream.Position - startPosition; 
       wrappedStream.Write(buffer, offset, count); 
       if (clonedStream.Position != relativeOffset) { 
        clonedStream.Position = relativeOffset; 
       } 
       clonedStream.Write(buffer, offset, count); 
      } 

      public override void Close() { 
       wrappedStream.Close(); 
       base.Close(); 
      } 

      protected override void Dispose(bool disposing) { 
       if (wrappedStream != null) { 
        wrappedStream.Dispose(); 
        wrappedStream = null; 
       } 
       base.Dispose(disposing); 
      } 
     } 
    } 
}