c# - tutorial - ¿Cómo obtengo la solicitud XML SOAP de una solicitud de servicio web de WCF?
wcf soap service c# (7)
Opción 1
Use el seguimiento / registro de mensajes .
opcion 2
Siempre puedes usar Fiddler para ver las solicitudes HTTP y la respuesta.
Opción 3
Use el rastreo de System.Net .
Estoy llamando a este servicio web dentro del código y me gustaría ver el XML, pero no puedo encontrar una propiedad que lo exponga.
Creo que quisiste decir que quieres ver el XML en el cliente, no rastrearlo en el servidor. En ese caso, su respuesta está en la pregunta que he vinculado anteriormente, y también en Cómo inspeccionar o modificar mensajes en el cliente . Pero, dado que la versión .NET 4 de ese artículo no tiene su C #, y el ejemplo de .NET 3.5 tiene cierta confusión (si no es un error), aquí se amplía para su propósito.
Puede interceptar el mensaje antes de que se apague usando un IClientMessageInspector :
using System.ServiceModel.Dispatcher;
public class MyMessageInspector : IClientMessageInspector
{ }
Los métodos en esa interfaz, BeforeSendRequest
y AfterReceiveReply
, le dan acceso a la solicitud y a la respuesta. Para usar el inspector, debe agregarlo a un IEndpointBehavior :
using System.ServiceModel.Description;
public class InspectorBehavior : IEndpointBehavior
{
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new MyMessageInspector());
}
}
Puede dejar los otros métodos de esa interfaz como implementaciones vacías, a menos que quiera usar su funcionalidad también. Lea el instructivo para obtener más detalles.
Después de crear una instancia del cliente, agregue el comportamiento al punto final. Usar nombres predeterminados del proyecto WCF de ejemplo:
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
client.Endpoint.Behaviors.Add(new InspectorBehavior());
client.GetData(123);
Establezca un punto de interrupción en MyMessageInspector.BeforeSendRequest()
; request.ToString()
está sobrecargado para mostrar el XML.
Si va a manipular los mensajes, debe trabajar en una copia del mensaje. Consulte Uso de la clase de mensaje para más detalles.
Gracias a la respuesta de Zach Bonham en otra pregunta para encontrar estos enlaces.
Estoy utilizando la siguiente solución para alojamiento de IIS en el modo de compatibilidad ASP.NET. Créditos al blog de MSDN de Rodney Viana.
Agregue los siguientes a su web.config bajo la configuración de la aplicación:
<add key="LogPath" value="C://logpath" />
<add key="LogRequestResponse" value="true" />
Reemplace su global.asax.cs con a continuación (también arregle el nombre del espacio de nombres):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using System.Text;
using System.IO;
using System.Configuration;
namespace Yournamespace
{
public class Global : System.Web.HttpApplication
{
protected static bool LogFlag;
protected static string fileNameBase;
protected static string ext = "log";
// One file name per day
protected string FileName
{
get
{
return String.Format("{0}{1}.{2}", fileNameBase, DateTime.Now.ToString("yyyy-MM-dd"), ext);
}
}
protected void Application_Start(object sender, EventArgs e)
{
LogFlag = bool.Parse(ConfigurationManager.AppSettings["LogRequestResponse"].ToString());
fileNameBase = ConfigurationManager.AppSettings["LogPath"].ToString() + @"/C5API-";
}
protected void Session_Start(object sender, EventArgs e)
{
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
if (LogFlag)
{
// Creates a unique id to match Rquests with Responses
string id = String.Format("Id: {0} Uri: {1}", Guid.NewGuid(), Request.Url);
FilterSaveLog input = new FilterSaveLog(HttpContext.Current, Request.Filter, FileName, id);
Request.Filter = input;
input.SetFilter(false);
FilterSaveLog output = new FilterSaveLog(HttpContext.Current, Response.Filter, FileName, id);
output.SetFilter(true);
Response.Filter = output;
}
}
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
}
protected void Application_Error(object sender, EventArgs e)
{
}
protected void Session_End(object sender, EventArgs e)
{
}
protected void Application_End(object sender, EventArgs e)
{
}
}
class FilterSaveLog : Stream
{
protected static string fileNameGlobal = null;
protected string fileName = null;
protected static object writeLock = null;
protected Stream sinkStream;
protected bool inDisk;
protected bool isClosed;
protected string id;
protected bool isResponse;
protected HttpContext context;
public FilterSaveLog(HttpContext Context, Stream Sink, string FileName, string Id)
{
// One lock per file name
if (String.IsNullOrWhiteSpace(fileNameGlobal) || fileNameGlobal.ToUpper() != fileNameGlobal.ToUpper())
{
fileNameGlobal = FileName;
writeLock = new object();
}
context = Context;
fileName = FileName;
id = Id;
sinkStream = Sink;
inDisk = false;
isClosed = false;
}
public void SetFilter(bool IsResponse)
{
isResponse = IsResponse;
id = (isResponse ? "Reponse " : "Request ") + id;
//
// For Request only read the incoming stream and log it as it will not be "filtered" for a WCF request
//
if (!IsResponse)
{
AppendToFile(String.Format("at {0} --------------------------------------------", DateTime.Now));
AppendToFile(id);
if (context.Request.InputStream.Length > 0)
{
context.Request.InputStream.Position = 0;
byte[] rawBytes = new byte[context.Request.InputStream.Length];
context.Request.InputStream.Read(rawBytes, 0, rawBytes.Length);
context.Request.InputStream.Position = 0;
AppendToFile(rawBytes);
}
else
{
AppendToFile("(no body)");
}
}
}
public void AppendToFile(string Text)
{
byte[] strArray = Encoding.UTF8.GetBytes(Text);
AppendToFile(strArray);
}
public void AppendToFile(byte[] RawBytes)
{
bool myLock = System.Threading.Monitor.TryEnter(writeLock, 100);
if (myLock)
{
try
{
using (FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
stream.Position = stream.Length;
stream.Write(RawBytes, 0, RawBytes.Length);
stream.WriteByte(13);
stream.WriteByte(10);
}
}
catch (Exception ex)
{
string str = string.Format("Unable to create log. Type: {0} Message: {1}/nStack:{2}", ex, ex.Message, ex.StackTrace);
System.Diagnostics.Debug.WriteLine(str);
System.Diagnostics.Debug.Flush();
}
finally
{
System.Threading.Monitor.Exit(writeLock);
}
}
}
public override bool CanRead
{
get { return sinkStream.CanRead; }
}
public override bool CanSeek
{
get { return sinkStream.CanSeek; }
}
public override bool CanWrite
{
get { return sinkStream.CanWrite; }
}
public override long Length
{
get
{
return sinkStream.Length;
}
}
public override long Position
{
get { return sinkStream.Position; }
set { sinkStream.Position = value; }
}
//
// For WCF this code will never be reached
//
public override int Read(byte[] buffer, int offset, int count)
{
int c = sinkStream.Read(buffer, offset, count);
return c;
}
public override long Seek(long offset, System.IO.SeekOrigin direction)
{
return sinkStream.Seek(offset, direction);
}
public override void SetLength(long length)
{
sinkStream.SetLength(length);
}
public override void Close()
{
sinkStream.Close();
isClosed = true;
}
public override void Flush()
{
sinkStream.Flush();
}
// For streamed responses (i.e. not buffered) there will be more than one Response (but the id will match the Request)
public override void Write(byte[] buffer, int offset, int count)
{
sinkStream.Write(buffer, offset, count);
AppendToFile(String.Format("at {0} --------------------------------------------", DateTime.Now));
AppendToFile(id);
AppendToFile(buffer);
}
}
}
Debe crear un archivo de registro en la carpeta LogPath con solicitud y respuesta XML.
Hay otra forma de ver XML SOAP: MessageEncoder personalizado . La diferencia principal de IClientMessageInspector es que funciona en un nivel inferior, por lo que captura el contenido de bytes original, incluido cualquier xml malformado.
Para implementar el rastreo utilizando este enfoque, debe envolver un textMessageEncoding estándar con un codificador de mensajes personalizado como un nuevo elemento de enlace y aplicar ese enlace personalizado al punto final en su config .
También puede ver como ejemplo cómo lo hice en mi proyecto: ajuste textMessageEncoding, logging encoder , custom binding element y config .
Simplemente podemos rastrear el mensaje de solicitud como.
OperationContext context = OperationContext.Current;
if (context != null && context.RequestContext != null)
{
Message msg = context.RequestContext.RequestMessage;
string reqXML = msg.ToString();
}
Solo quería agregar esto a la respuesta de Kimberly. Tal vez puede ahorrar algo de tiempo y evitar errores de compilación por no implementar todos los métodos que requiere la interfaz IEndpointBehaviour.
Atentamente
Nicki
/*
// This is just to illustrate how it can be implemented on an imperative declarared binding, channel and client.
string url = "SOME WCF URL";
BasicHttpBinding wsBinding = new BasicHttpBinding();
EndpointAddress endpointAddress = new EndpointAddress(url);
ChannelFactory<ISomeService> channelFactory = new ChannelFactory<ISomeService>(wsBinding, endpointAddress);
channelFactory.Endpoint.Behaviors.Add(new InspectorBehavior());
ISomeService client = channelFactory.CreateChannel();
*/
public class InspectorBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
// No implementation necessary
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new MyMessageInspector());
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
// No implementation necessary
}
public void Validate(ServiceEndpoint endpoint)
{
// No implementation necessary
}
}
public class MyMessageInspector : IClientMessageInspector
{
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
// Do something with the SOAP request
string request = request.ToString();
return null;
}
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
// Do something with the SOAP reply
string replySoap = reply.ToString();
}
}
OperationContext.Current.RequestContext.RequestMessage
este contexto es accesible desde el lado del servidor durante el procesamiento de la solicitud. Esto no funciona para operaciones unidireccionales