9

我有一个应用程序,它使用由服务引用生成的 ClientBase 对象来调用第三方 WCF SOAP 服务。每隔一段时间,服务调用就会返回一个错误异常,而不是带有“处理请求时发生错误”的异常消息,这是完全通用的。

即使在服务错误期间,也应该有一个随响应返回的跟踪 ID 值,以便该服务的开发人员可以调试/解决任何问题。因此,理想情况下,我想要记录在发生异常时返回到我的 ClientBase 对象的原始响应。如果可能的话,我不想记录每条消息,那将是过度的 IMO。

有没有办法使用 ClientBase 来捕获它?也许有一些包含原始响应内容的上下文对象?如果可能的话,这需要内置到我的应用程序中。我知道有一些工具可以充当客户端和服务之间的代理,可以记录 http 请求/响应,但这不是我所追求的。

4

2 回答 2

18

就其ClientBase本身而言,没有地方可以获取该信息。但是您可以在客户端 ( ) 添加一个自定义消息检查IClientMessageInspector器,您可以在其中查看所有正在接收的消息;对于这些消息,您可以检查IsFault属性,如果为真,则根据需要记录消息。

更新:添加示例代码

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();
    }
}
于 2012-10-11T17:31:39.077 回答
0

您可以考虑另一种捕获 XML自定义 MessageEncoder的方法。不像IClientMessageInspector它处理http 正文的原始字节内容

您需要使用自定义消息编码器将标准textMessageEncoding包装为新的绑定元素,并将该自定义绑定应用于您的config中的端点。

你也可以看看我在我的项目中是如何做到的—— 包装textMessageEncoding、日志编码器、自定义绑定元素配置

于 2018-10-06T16:05:25.270 回答