2008-11-01 84 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); 
      } 
     } 
    } 
}