September 19, 2022

How to trace soap xml from Web Service client?

In this post I will explain how to trace the raw xml for each request and response sent between client/server for Soap/WCF Services.

I found this idea/code from stackoverflow post:

how to trace soap xml as a webservice client in netcore? .

You need to create two classes

  1. One is InspectorBehavior to implment IEndpointBehavior interface.
  2. Second is MyMessageInspector which implements the IClientMessageInspector interface.

The InspectorBehavior class will use the ApplyClientBehavior() method to add the real message inspector by calling Add() method on ClientMessageInspectors collection for clientRuntime object.

clientRuntime.ClientMessageInspectors.Add(myMessageInspector);

Further in MyMessageInspector class, we can retreive and save the Request and Response Xml content in local variables/properties in these two methods.

  • BeforeSendRequest
  • AfterReceiveReply

Complete code listing for MyMessageInspector class is:

public class MyMessageInspector : IClientMessageInspector
{
   public string LastRequestXML { get; private set; }
   public string LastResponseXML { get; private set; }

   public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, 
                                 object correlationState)
   {
      LastResponseXML = reply.ToString();
   }

   public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, 
                                   System.ServiceModel.IClientChannel channel)
   {
      LastRequestXML = request.ToString();
      return request;
   }
}

Code listing for InspectorBehavior class is:

public class InspectorBehavior : IEndpointBehavior
{
   public string LastRequestXML
   {
      get
      {
         return myMessageInspector.LastRequestXML;
      }
   }

   public string LastResponseXML
   {
      get
      {
         return myMessageInspector.LastResponseXML;
      }
   }

   private MyMessageInspector myMessageInspector = new MyMessageInspector();

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

   }

   public void ApplyDispatchBehavior(ServiceEndpoint endpoint, 
               EndpointDispatcher endpointDispatcher)
   {

   }

   public void Validate(ServiceEndpoint endpoint)
   {

   }

   public void ApplyClientBehavior(ServiceEndpoint endpoint, 
               ClientRuntime clientRuntime)
   {
      clientRuntime.ClientMessageInspectors.Add(myMessageInspector);
   }
}

I used the WFC service instance created by Visual Studio template with default two methods GetData() and GetDataUsingDataContract();

When calling the service methods on the client side, you can simply add the custom EndpointBehavior (InspectorBehavior) on the service client instance object.

ServiceReference1.Service1Client service1Client = new ServiceReference1.Service1Client();

var requestInterceptor = new InspectorBehavior();
service1Client.Endpoint.EndpointBehaviors.Add(requestInterceptor);

After service method call, you can get the Request and Response Xml content by requestInterceptor's properties:

string str1 = service1Client.GetDataAsync(1).GetAwaiter().GetResult();
string req1Xml = requestInterceptor.LastRequestXML;
string res1Xml = requestInterceptor.LastResponseXML;

Here is the sample of raw sample I received by above call.

Request

<?xml version="1.0" encoding="utf-16"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none"
    >http://tempuri.org/IService1/GetData</Action>
  </s:Header>
  <s:Body>
    <GetData xmlns="http://tempuri.org/">
      <value>1</value>
    </GetData>
  </s:Body>
</s:Envelope>

Response

<?xml version="1.0" encoding="utf-16"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header />
  <s:Body>
    <GetDataResponse xmlns="http://tempuri.org/">
      <GetDataResult>You entered: 1</GetDataResult>
    </GetDataResponse>
  </s:Body>
</s:Envelope>

Call the second method, and get the Request and Response Xml content by same properties:

ServiceReference1.CompositeType compositeType = new ServiceReference1.CompositeType();
compositeType.BoolValue = true;
compositeType.StringValue = "some text";

ServiceReference1.CompositeType compositeTypeRes = 
       service1Client.GetDataUsingDataContractAsync(compositeType).GetAwaiter().GetResult();
string req2Xml = requestInterceptor.LastRequestXML;
string res2Xml = requestInterceptor.LastResponseXML;

Here is the sample of raw sample I received by above call.

Request

<?xml version="1.0" encoding="utf-16"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none"
    >http://tempuri.org/IService1/GetDataUsingDataContract</Action>
  </s:Header>
  <s:Body>
    <GetDataUsingDataContract xmlns="http://tempuri.org/">
      <composite xmlns:d4p1="http://schemas.datacontract.org/2004/07/WcfService1" 
      xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <d4p1:BoolValue>true</d4p1:BoolValue>
        <d4p1:StringValue>some text</d4p1:StringValue>
      </composite>
    </GetDataUsingDataContract>
  </s:Body>
</s:Envelope>

Response

<?xml version="1.0" encoding="utf-16"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header />
  <s:Body>
    <GetDataUsingDataContractResponse xmlns="http://tempuri.org/">
      <GetDataUsingDataContractResult xmlns:a="http://schemas.datacontract.org/2004/07/WcfService1" 
      xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <a:BoolValue>true</a:BoolValue>
        <a:StringValue>some textSuffix</a:StringValue>
      </GetDataUsingDataContractResult>
    </GetDataUsingDataContractResponse>
  </s:Body>
</s:Envelope>

References:

Related Post(s):

1 comment: