Как получить доступ к ответу SOAP - PullRequest
11 голосов
/ 02 ноября 2008

(Если что-то здесь нужно уточнить / более подробно, пожалуйста, дайте мне знать.)

У меня есть приложение (C #, 2. * framework), которое взаимодействует со сторонним веб-сервисом с использованием SOAP. Я использовал WSCF-надстройку thinktecture против поставляемого WSDL для создания реализации на стороне клиента. По независящим от меня причинам обмен сообщениями SOAP использует WSE2.0 для безопасности (реализация thinctecture должна была быть изменена, чтобы включить ссылку на WSE2.0). В дополнение к «обычному» пакету данных я прикрепляю сохраненный сертификат X509 и двоичный токен безопасности от предыдущего вызова к другому веб-сервису. Мы используем какое-то SSL-шифрование - я не знаю деталей.

Вся необходимая сериализация / десериализация содержится в клиенте веб-службы - то есть, когда мне после вызова клиента возвращается управление, вся строка XML, содержащаяся в ответе SOAP, недоступна мне - только десериализованные компоненты. Не поймите меня неправильно - я думаю, что это хорошо, потому что это означает, что мне не нужно делать это самому.

Однако для того, чтобы у меня было что-то, что стоит хранить / архивировать, мне нужно повторно сериализовать данные в корневом элементе. Это кажется пустой тратой ресурсов, так как мой результат был в ответе SOAP.

Теперь на мой вопрос: Как я могу получить доступ к «чистой» версии ответа SOAP, чтобы мне не пришлось повторно сериализовать все для хранения / архивирования?

Редактировать. Мое приложение - это «бесформенное» приложение для Windows, работающее в качестве сетевой службы, которое запускается монитором триггера клиента WebsphereMQ. Я не думаю, что ASP.NET решения будут применяться.

Правка. Поскольку до сих пор существует общее мнение о том, что не имеет значения, является ли мое приложение ASP.NET или нет, я предоставлю решение CodeMelt (и, соответственно, Криса).

Ответы [ 4 ]

8 голосов
/ 02 ноября 2008

Вы можете использовать SoapExtension из существующей платформы WSE2.0 для перехвата ответов от сервера.

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 в объекты.

Пример регистрации всего трафика для веб-службы из MSDN

7 голосов
/ 03 марта 2011

Вот пример, который вы можете настроить с помощью веб-ссылки Visual studio на http://footballpool.dataaccess.eu/data/info.wso?WSDL

По сути, вы должны вставить в цепочку вызовов веб-сервиса спайлер XmlReader, который восстановит необработанный 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 голосов
/ 07 декабря 2011

Вдохновленный 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);
            }
        }
    }
}
0 голосов
/ 02 ноября 2008

Библиотека MSDN содержит пример кода для получения XML-запроса и ответа, который можно использовать для его архивирования. Очевидно, вам придется внести некоторые изменения, поскольку пример хранит данные в текстовом файле, но это не слишком сложно.

...