Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Logging SOAP Raw Response Received by a ClientBase object

Tags:

soap

logging

wcf

I have an application that uses a ClientBase object generated by a service reference to call a third party WCF SOAP service. Every once in awhile, the service call returns a fault exception instead with an exception message of "An error occurred while processing the request" which is completely generic.

Even during service errors, there is supposed to be a trace ID value that comes back with the response so the developers of that service can debug/troubleshoot any issues. So, what I ideally want is to log the raw response that comes back to my ClientBase object when there is an exception. I don't want to log every single message if possible, that would be overkill IMO.

Is there a way to capture that using the ClientBase? Maybe there's some context object that contains the raw response content? This needs to be built into my application if possible. I know there are tools out there that act as a proxy between the client and service that can log http requests/responses but that is not what I'm after.

like image 214
Jeff LaFay Avatar asked Oct 11 '12 14:10

Jeff LaFay


1 Answers

At the ClientBase itself there's no place where you can get that information. But you can add a custom message inspector at the client (IClientMessageInspector) where you can see all the messages that are being received; for those messages you can check the IsFault property, and if true log the message as you want.

Update: Adding sample code

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

public class StackOverflow_12842014
{
    [ServiceContract]
    public interface ITest
    {
        [OperationContract]
        string Echo(string text);
    }
    public class Service : ITest
    {
        public string Echo(string text)
        {
            if (text == "throw") throw new ArgumentException("Throwing as requested");
            return text;
        }
    }
    class MyClient : ClientBase<ITest>, ITest
    {
        public MyClient(Binding binding, EndpointAddress address)
            : base(binding, address)
        {
            this.Endpoint.Behaviors.Add(new MyFaultLogger());
        }

        public string Echo(string text)
        {
            return this.Channel.Echo(text);
        }

        class MyFaultLogger : IEndpointBehavior, IClientMessageInspector
        {
            public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
            {
            }

            public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
            {
                clientRuntime.MessageInspectors.Add(this);
            }

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

            public void Validate(ServiceEndpoint endpoint)
            {
            }

            public void AfterReceiveReply(ref Message reply, object correlationState)
            {
                if (reply.IsFault)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("Fault received!: {0}", reply);
                    Console.ResetColor();
                }
            }

            public object BeforeSendRequest(ref Message request, IClientChannel channel)
            {
                return null;
            }
        }
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
        host.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;
        host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "");
        host.Open();
        Console.WriteLine("Host opened");

        MyClient client = new MyClient(new BasicHttpBinding(), new EndpointAddress(baseAddress));

        Console.WriteLine(client.Echo("Hello"));
        try
        {
            Console.WriteLine(client.Echo("throw"));
        }
        catch (Exception)
        {
            Console.WriteLine("The fault should have been traced");
        }

        client.Close();

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}
like image 174
carlosfigueira Avatar answered Oct 20 '22 06:10

carlosfigueira