viernes, 21 de septiembre de 2012

WCF - Interceptar y manipular mensaje soap Cliente usando Message Inspector en tiempo de ejecución

En la mayoría de los casos WCF permite mediante la clase MessageContract modificar el mensaje soap. Si cliente y servidor son WCF no debería haber problema para manipular el mensaje usando MessageContract y sin duda es el modo más elegante de personalizar un mensaje pero a efectos de interoperabilidad no es aplicable en todos los escenarios.

WCF Extensibility proporciona herramientas con el objetivo que el desarrollador pueda personalizar el comportamiento de diversos aspectos de los servicios como seguridad, hosting, serialización, publicación de metadatos, canales...

En concreto en este artículo veremos como crear un Message Inspector personalizado y lo añadiremos a nuestro cliente WCF. El objetivo de Message Inspector es tener acceso a todos los mensajes de salida y entrada que procesa el cliente para manipular algún aspecto del mensaje soap.

En primer lugar crearemos una clase AreaTICMessageInspector:

    public class AreaTICMessageInspector: IDispatchMessageInspector, IClientMessageInspector
    {
        public AreaTICMessageInspector()
        {

        }

        #region IDispatchMessageInspector Members

        public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
        {
            return null;
        }

        public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
        {
        }

        #endregion

        #region IClientMessageInspector Members

        public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
        {

        }

        public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
        {
            //Copiamos objeto request para poder modificarlo
            Message newMessage = null;
            MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
            request = buffer.CreateMessage();

            //obtenemos Xml del request
            XmlDocument oDoc = new XmlDocument();
            using (XmlWriter writer = oDoc.CreateNavigator().AppendChild())
            {
                request.WriteMessage(writer);
                writer.Close();
            }

            //Manipulamos XML mensaje
            //oDoc.Nodes.Add(...) o oDoc.Nodes[0].Attributes...

            //Damos el "cambiazo" de request original por el modificado
            XmlNodeReader reader = new XmlNodeReader(oDoc);
            newMessage = Message.CreateMessage(reader, int.MaxValue, request.Version);
            request = newMessage;

            return null;
        }

        #endregion
    }
}
En el ejemplo hemos implementado el método BeforeSendRequest que nos permite controlar el mensaje de salida en cliente. Si queremos manipular también la respuesta tendríamos que implementar AfterReceiveReply.

En segundo lugar hemos de crear una clase AreaTICMessageInspector, es importante implementar la interface IEndPointBehavior.

namespace AreaTIC
{
    [AttributeUsage(AttributeTargets.Class)]
    public class AreaTICMessageInspectorBehavior : Attribute, IEndpointBehavior
    {
        public AreaTICMessageInspectorBehavior() : base() 
        { 

        }

        #region IEndpointBehavior Members

        public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        {
            IClientMessageInspector inspector = null;
            inspector = new AreaTICMessageInspector();
            clientRuntime.MessageInspectors.Add(inspector);
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
        {
            //no es necesaria su implementación en cliente.
        }

        public void Validate(ServiceEndpoint endpoint)
        {
            //no es necesaria su implementación en cliente.
        }

        #endregion
    }
}
Por último hemos de añadir en tiempo de ejecución el EndPointBehavior personalizado al EndPoint que usa el cliente para comunicar:

      client.Endpoint.Behaviors.Add(new AreaTICMessageInspectorBehavior());
Espero que os sea útil este artículo, dentro de areaTIC puedes encontrar otros artículos interesantes, no dudes en consultar nuestro archivo.


4 comentarios:

Anónimo dijo...

simplemente genial

Anónimo dijo...

Hola. ¿Dónde va la línea client.Endpoint.Behaviors.Add(new AreaTICMessageInspectorBehavior());?
Saludos.

Carlos Cañizares dijo...

Buenas, se refiere al cliente del servicio (el service reference que usas en presentación por decirlo de algún modo)

TI dijo...
Este comentario ha sido eliminado por el autor.

Publicar un comentario