Reading SOAP / WCF client Request XML Response XML And HTTP Headers with system.servicemodel behavior and message inspector

To troubleshoot issues you need to log SOAP request, response XML, and response HTTP headers. You can use an endpoint behavior and a message inspector to achieve it.

See the below sample — it will call a public service: https://www.crcind.com/csp/samples/SOAP.Demo.cls

Project File

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="System.ServiceModel.Http" Version="8.1.2" />
  </ItemGroup>

</Project>

Program.cs

using SoapAddIntegerDemo;
using System;
using System.ServiceModel;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        var binding = new BasicHttpBinding();
        binding.Security.Mode = BasicHttpSecurityMode.Transport;
        var behavior = new SoapInspectorBehavior();

        var address = new EndpointAddress("https://www.crcind.com/csp/samples/SOAP.Demo.cls");
        var client = new SoapDemoClient(binding, address);
        client.Endpoint.EndpointBehaviors.Add(behavior);

        var result = await client.AddIntegerAsync(1, 2);
        Console.WriteLine($"Received Result :  {result}");
        Console.WriteLine($"Soap Request :  {behavior.LastRequestXml}");
        Console.WriteLine($"Soap Response :  {behavior.LastResponseXml}");
        Console.WriteLine($"Soap response headers :  {behavior.LastHeaders}");

        Console.ReadLine();
    }
}

SoapMessageInspector.cs

using System.Net;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Text;

public class SoapMessageInspector : IClientMessageInspector
{
    public string LastRequestXml { get; private set; } = null!;
    public string LastResponseXml { get; private set; } = null!;
    public string LastHeaders { get; private set; } = "No Headers received";

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        LastRequestXml = request.ToString();
        return request;
    }

    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
        LastResponseXml = reply.ToString();
        foreach (var property in reply.Properties)
        {
            if (property.Value is not HttpResponseMessageProperty httpProperties) continue;

            var sb = new StringBuilder();
            var headers = (WebHeaderCollection)httpProperties.Headers;
            foreach (var headerName in headers.AllKeys)
            {
                sb.AppendLine($"{headerName}: {headers[headerName]}");
            }
            LastHeaders = sb.ToString();
        }
    }
}

SoapInspectorBehavior.cs

using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

public class SoapInspectorBehavior : IEndpointBehavior
{
    private readonly SoapMessageInspector _inspector = new();

    public string LastRequestXml => _inspector.LastRequestXml;
    public string LastResponseXml => _inspector.LastResponseXml;
    public string LastHeaders => _inspector.LastHeaders;

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

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

    public void Validate(ServiceEndpoint endpoint) { }

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

SoapDemoClient.cs

using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Threading.Tasks;

namespace SoapAddIntegerDemo;

[ServiceContract(Namespace = "http://tempuri.org")]
public interface ISoapDemo
{
    [OperationContract(Action = "http://tempuri.org/SOAP.Demo.AddInteger", ReplyAction = "*")]
    Task<long> AddIntegerAsync(long Arg1, long Arg2);
}

public class SoapDemoClient : ClientBase<ISoapDemo>, ISoapDemo
{
    public SoapDemoClient(Binding binding, EndpointAddress address)
        : base(binding, address)
    {
    }

    public Task<long> AddIntegerAsync(long Arg1, long Arg2)
        => Channel.AddIntegerAsync(Arg1, Arg2);
}

Comments

Popular posts from this blog

Welcome

Tool - excalidraw - Draw sequence diagrams flow charts