tutorial servicio crear consumir consume cliente c# xml web-services soap wse2.0

servicio - web service soap c#



¿Cómo obtengo acceso a la respuesta SOAP? (4)

Puede utilizar SoapExtension del marco WSE2.0 existente para interceptar las respuestas del servidor.

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..."); } } }

En la etapa de SoapMessageStage.BeforeDeserialize, puede leer los datos esperados que desee de oldstream (por ejemplo, use XmlReader). Luego, almacene los datos esperados en algún lugar para que los use y también necesita reenviar los datos de la transmisión anterior a la etapa posterior del servicio web para utilizar los datos, por ejemplo, deserializar XML en objetos.

La muestra de registrar todo el tráfico para el servicio web de MSDN

(Si algo aquí necesita aclaración / más detalles, por favor hágamelo saber).

Tengo una aplicación (C #, 2. * framework) que interactúa con un servicio web de terceros que usa SOAP. Usé el complemento WSCF de thinktecture contra un WSDL suministrado para crear la implementación del lado del cliente. Por razones ajenas a mi control, el intercambio de mensajes SOAP usa WSE2.0 para la seguridad (la implementación de la arquitectura temporal tuvo que ser modificada para incluir la referencia WSE2.0). Además del paquete de datos ''normal'', adjunto un certificado X509 almacenado y un token de seguridad binario de una llamada anterior a un servicio web diferente. Estamos utilizando el cifrado SSL de algún tipo; no sé los detalles.

Toda la serialización / deserialización necesaria está contenida en el cliente del servicio web, es decir, cuando me devuelven el control después de llamar al cliente, toda la cadena XML contenida en la respuesta SOAP no está disponible para mí, solo los componentes deserializados. No me malinterpreten, creo que eso es bueno porque significa que no tengo que hacerlo yo mismo.

Sin embargo, para que tenga algo que valga la pena almacenar / archivar, tengo que volver a serializar los datos en el elemento raíz. Esto parece una pérdida de recursos ya que mi resultado fue en la respuesta SOAP.

Ahora, para mi pregunta: ¿cómo puedo obtener acceso a una versión ''clara'' de la respuesta SOAP para que no tenga que volver a serializar todo para el almacenamiento / archivo?

Editar- Mi aplicación es una aplicación de Windows ''sin forma'' que se ejecuta como un servicio de red, desencadenada por un monitor desencadenante del cliente WebsphereMQ. No creo que se apliquen las soluciones de ASP.NET.

Editar - Dado que el consenso hasta ahora es que no importa si mi aplicación es ASP.NET o no, le daré una oportunidad a la solución de CodeMelt (y por extensión Chris).


MSDN Library incluye un código de ejemplo para obtener el XML de la solicitud y la respuesta que puede usar para archivarlo. Obviamente, deberá realizar algunos cambios, ya que el ejemplo almacena datos en un archivo de texto, pero no es demasiado complicado.


Inspirado por jfburdet, quería ver si era posible interceptar directamente a nivel de secuencia / byte en lugar de reconstruir XML. ¡Y es! Vea el código a continuación:

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); } } } }


Aquí hay un ejemplo que puede configurar usando la referencia web de Visual Studio a http://footballpool.dataaccess.eu/data/info.wso?WSDL

Básicamente, debe insertar en la cadena de llamadas del servicio web un spyer XmlReader que reconstruirá el XML sin formato.

Creo que de alguna manera es más simple que usar SoapExtensions.

La solución de solución se inspiró en 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(); } } }