Como guardar en un archivo el contenido de los mensajes SOAP para la referencia de un servicio web

.NET nos permite crear referencias a servicios Web con mucha facilidad y se encarga de todos los mensajes SOAP necesarios para llamar a estos servicios, pero en ocasiones necesitamos conocer el contenido de estos mensajes para resolver problemas o porque el proveedor del servicio nos pide uno de estos mensajes para ayudarnos a resolver alguna situación.

En este tutorial encontrarás la forma que yo utilizo para interceptar estos mensajes y grabarlos en un archivo. El procedimiento es sencillo y te lo describo a continuación.

Behaviors

Significa “comportamientos” y es de esta manera en la que podemos cambiar la forma en la que se crean los mensajes SOAP a utilizar en los servicios web. Usando este mecanismo podemos modificar el mensaje o (en nuestro caso) grabarlo a disco.

Para crear el Behavior, primero debemos crear un Inspector de la siguiente manera:

using System.ServiceModel.Dispatcher;
public class LogMessagesInspector : IClientMessageInspector
{
    /// <summary>
    /// Ocurre cuando estamos por enviar el mensaje al servidor.
    /// </summary>
    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        // quiero un archivo para cada mensaje, por ello utilizo un GUID en el nombre
        string filename = string.Format("C:\\Logs\\{0}.request.soap", System.Guid.NewGuid().ToString());

        // esta configuración hace que el archivo se guarde en UTF8
        XmlWriterSettings settings = new XmlWriterSettings() {
            Encoding = System.Text.Encoding.UTF8
        };

        // no debemos leer el mesaje directamente, por lo que creamos una copia
        using (MessageBuffer buffer = request.CreateBufferedCopy(65536))
        {
            // esta copia no tiene formato, así que creamos un mensaje usando la copia
            using (Message msg = buffer.CreateMessage())
            {
                // este "writer" se encargará de escribir el contenido en el archivo
                using (var writer = System.Xml.XmlWriter.Create(filename, settings))
                {
                    msg.WriteMessage(writer);
                }
            }
        }
        return null;
    }

    /// <summary>
    /// Ocurre cuando recibimos el mensaje de vuelta del servidor.
    /// </summary>
    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
        // quiero un archivo para cada mensaje, por ello utilizo un GUID en el nombre
        string filename = string.Format("C:\\Logs\\{0}.response.soap", System.Guid.NewGuid().ToString());

        // esta configuración hace que el archivo se guarde en UTF8
        XmlWriterSettings settings = new XmlWriterSettings()
        {
            Encoding = System.Text.Encoding.UTF8
        };

        // no debemos leer el mesaje directamente, por lo que creamos una copia
        using (MessageBuffer buffer = reply.CreateBufferedCopy(65536))
        {
            // esta copia no tiene formato, así que creamos un mensaje usando la copia
            using (Message msg = buffer.CreateMessage())
            {
                // este "writer" se encargará de escribir el contenido en el archivo
                using (var writer = System.Xml.XmlWriter.Create(filename, settings))
                {
                    msg.WriteMessage(writer);
                }
            }
        }
    }

}

Observa que el Inspector tiene las dos rutinas que nos interesan: BeforeSendRequest y AfterReceiveReply. En el código documenté la forma en la que funcionan. Toma en cuenta que el código puede simplificarse, pero lo puse de esta manera para que quede claro lo que hace cada rutina.

En mi caso, yo quería que cada mensaje se grabe en un archivo independiente, por eso utilicé la clase System.Guid para generar un valor diferente en cada llamada, pero tu ajusta la rutina a como mejor te parezca.

Ya con el Inspector, ahora creamos el Behavior de la siguiente manera:

public class LogMessagesBehavior : IEndpointBehavior
{
    public void Validate(ServiceEndpoint endpoint) { }

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        // esta rutina inyecta el inspector en la referencia del servicio
        clientRuntime.MessageInspectors.Add(new LogMessagesInspector());
    }
}

Este Behavior utiliza el inspector que hemos creado y lo inyecta en las instancias de la referencia al servicio web, todo esto de forma automática. Así de sencillo está el asunto.

Cómo utilizarlo en tu servicio

Para utilizar el Behavoir que hemos creado, necesitamos modificar el código que crea esta referencia para contemplar lo siguiente:

// esta línea crea el cliente al servicio web que necesitamos
MiServicioPortTypeClient servicio = new MiServicioPortTypeClient();

// aquí le especificamos que debe utilizar el behavior
servicio.Endpoint.Behaviors.Add(new LogMessagesBehavior());

La solución es bastante sencilla como puedes ver y puedes modificarla de acuerdo a tus necesidades. Espero que te sea de utilidad.


Posted

in

,

by

Comments

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *