Intercept raw soap messages in code using WCF

Intercept raw soap messages in code using WCF

I faced the problem today that I needed to intercept the soap messages that are send to a webservice using WCF. To make things more complicated I needed to have them as a variable in my code and most of the stuff I found online was how to enable tracing/logging. A very good example to enable tracing is found on this website.

After some extensive google’ing I came across this post.
The post does an excellent job of describing how you can capture and use the raw soap messages in your code. I will try not to just shamelessly copy the post (although some pieces will be the same) but rather try to describe how I implemented it.

First I made a class that holds the soap messages, I put them all in one cs file called MessageInspector.

public class InspectedSOAPMessages
{
    public string Request { get; set; }
    public string Response { get; set; }
}

Next create a IClientMessageInspector, this class actually captures the messages

/// /// Actual inspector that captures the messages
/// 
public class CapturingMessageInspector : IClientMessageInspector
{
    ///     /// Holds the messages
    /// 
    public InspectedSOAPMessages SoapMessages { get; set; }

    public CapturingMessageInspector(InspectedSOAPMessages soapMessages)
    {
        this.SoapMessages = soapMessages;
    }

    ///     /// Called after the web service call completes.  Allows capturing of raw response.    
    /// 
    public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
    {
        this.SoapMessages.Response = reply.ToString();
    }

    ///     /// Called before the web service is invoked.  Allows capturing of raw request.
    /// 
    public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel)
    {
        this.SoapMessages.Request = request.ToString();
        return null;
    }
}

The last thing to add is a custom endpoint, this will use the message inspector class above.

/// /// Allows capturing of raw SOAP Messages
/// 
public class CapturingEndpointBehavior : IEndpointBehavior
{
    ///     /// Holds the messages
    /// 
    public InspectedSOAPMessages SoapMessages { get; set; }

    public CapturingEndpointBehavior(InspectedSOAPMessages soapMessages)
    {
        this.SoapMessages = soapMessages;
    }

    ///     /// Required by IEndpointBehavior
    /// 
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { return; }

    ///     /// Required by IEndpointBehavior
    /// 
    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.MessageInspectors.Add(new CapturingMessageInspector(this.SoapMessages));
    }

    ///     /// Required by IEndpointBehavior
    /// 
    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { return; }

    ///     /// Required by IEndpointBehavior
    /// 
    public void Validate(ServiceEndpoint endpoint) { return; }
}

Next up using the above classes. This turned out to be pretty easy.
When you create your client, add the new endpoint behaviour.

//I've extended the existing WCF generated class with my own GetClientMethod
public partial class SigServicePortTypeClient
{
    public static SigServicePortTypeClient GetClient(InspectedSOAPMessages soapMessages)
    {
        SigServicePortTypeClient client = new SigServicePortTypeClient();
        client.Endpoint.Behaviors.Add(new CapturingEndpointBehavior(soapMessages));
        client.Endpoint.Contract.ProtectionLevel = ProtectionLevel.Sign;
        return client;
    }
}

public partial class GetSig
{
    public GetSigResp Ask()
    {
        InspectedSOAPMessages soapMessages = new InspectedSOAPMessages();
        try
        {
            var client = SigServicePortTypeClient.GetClient(soapMessages);
            var response = client.getSig(this);
            return response;
        }
        catch (Exception ex)
        {
            //Return the error, but with an inner exception containing the soap message (response)
            Exception newEx = new Exception(ex.Message, new Exception(soapMessages.Response));
            throw newEx;
        }
    }
}

Thats it, when there is an error, you should have an inner exception with the response soap message.

Leave a Reply

Your email address will not be published. Required fields are marked *