wcf:自定义消息检查器未连接

时间:2013-05-15 08:37:31

标签: c# wcf

我在服务端做了一个自定义错误处理程序:

 public class GlobalErrorHandler : Attribute, IErrorHandler, IServiceBehavior
    {
        public void AddBindingParameters(
            ServiceDescription serviceDescription,
            ServiceHostBase serviceHostBase,
            Collection<ServiceEndpoint> endpoints,
            BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            IErrorHandler errorHandler = new GlobalErrorHandler();

            foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
            {
                ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;

                if (channelDispatcher != null)
                {
                    channelDispatcher.ErrorHandlers.Add(errorHandler);

                }
            }
        }

        public bool HandleError(Exception error)
        {
            Trace.TraceError(error.ToString());

            if (error is FaultException)
                return false; // Let WCF do normal processing
            else
                return true; // Fault message is already generated
        }

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
        }

        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            if (error is FaultException)
            {
                // Let WCF do normal processing
            }
            else
            {
                // Generate fault message manually
                MessageFault messageFault = MessageFault.CreateFault(
                    new FaultCode("Sender"), new FaultReason(error.Message),
                    error, new NetDataContractSerializer());
                fault = Message.CreateMessage(version, messageFault, null);
            }
        }

    }

    public class ErrorHandlerElement : BehaviorExtensionElement
    {
        protected override object CreateBehavior()
        {
            return new GlobalErrorHandler();
        }

        public override Type BehaviorType
        {
            get { return typeof (GlobalErrorHandler); }
        }
    }

我在客户端定义了一个自定义消息检查器:

public class MessageInspector : IClientMessageInspector
    {
        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
            if (reply.IsFault)
            {
                //do some processing
            }
        }

        public object BeforeSendRequest(ref Message request, System.ServiceModel.IClientChannel channel)
        {
            return null;
        }
}

我有一个自定义行为,用于连接消息检查器:

public class NewtonsoftJsonBehavior : WebHttpBehavior
{
 public override void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime       clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(new MessageInspector());
        }
}

并且通过工厂以编程方式应用此行为:

public class JsonWebServiceHostFactory : WebServiceHostFactory
    {
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            var host =  base.CreateServiceHost(serviceType, baseAddresses);
            //return host;
            //ServiceEndpoint ep = host.AddServiceEndpoint(serviceType, new WebHttpBinding(), "");
            //host.Description.Endpoints[0].Behaviors.Add(new WebHttpBehavior { HelpEnabled = true });     
            //return host;

            WebHttpBinding webBinding = new WebHttpBinding();

            host.AddServiceEndpoint(serviceType, webBinding, "").Behaviors.Add(new NewtonsoftJsonBehavior());
            return host;
        }
    }

然而,当我调试并在服务中生成faultexception时,会调用globalerrorhandler,但调试器永远不会进入消息检查器。 知道为什么吗?

2 个答案:

答案 0 :(得分:3)

要在WCF服务端创建Message Inspector,请使用IDispatchMessageInspector的实现,而不是IClientMessageInspector

一个例子:

<强>服务

EndpointAddress endpoint = new EndpointAddress("http://localhost:9001/Message");

WebServiceHost svcWebHost = new WebServiceHost(typeof(Service.Message), endpoint.Uri);

CustomServiceBehavior serviceBehavior = new CustomServiceBehavior();
svcWebHost.Description.Behaviors.Add(serviceBehavior);

Binding webHttpBinding = new WebHttpBinding();

ServiceEndpoint serviceEndpoint = svcWebHost.AddServiceEndpoint(typeof(Service.IMessage), webHttpBinding, endpoint.Uri);

ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
svcWebHost.Description.Behaviors.Add(smb);

ServiceDebugBehavior sdb = svcWebHost.Description.Behaviors.Find<ServiceDebugBehavior>();
sdb.IncludeExceptionDetailInFaults = true;

svcWebHost.Open();

服务合同

[ServiceContract]
public interface IMessage
{
    [OperationContract]
    [WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
    Model.TestResponse Test();
}

服务实施

public class Message : IMessage
{
    public Model.TestResponse Test()
    {
        return new Model.TestResponse() { success = true, message = "OK!" };
    }
}

CustomServiceBehavior实现了IServiceBehavior:

public class CustomServiceBehavior : IServiceBehavior
{
    public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    {

    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
    {
        CustomEndpointBehavior endpointBehavior = new CustomEndpointBehavior();
        foreach (var endpoint in serviceDescription.Endpoints)
            endpoint.EndpointBehaviors.Add(endpointBehavior);
    }

    public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
    {

    }
}

CustomEndpointBehavior实现IEndpointBehavior

public class CustomEndpointBehavior : IEndpointBehavior
{
    public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    {

    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
    {

    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
    {
        var inspector = new CustomDispatchMessageInspector();
        endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
    }

    public void Validate(ServiceEndpoint endpoint)
    {

    }
}

CustomDispatchMessageInspector实现IDispatchMessageInspector

public class CustomDispatchMessageInspector : IDispatchMessageInspector
{
    public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
    {
        return null;
    }

    public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
    {
        var httpResponse = ((HttpResponseMessageProperty)reply.Properties["httpResponse"]);
        httpResponse.Headers.Add("user-agent", "My Browser");
    }
}

此示例是一个WCF自托管,没有配置文件(在代码中配置WCF服务),它返回一个Json并在HTTP响应中发送自定义标头(用户代理:我的浏览器)。

测试此代码:

  1. 创建Windows控制台应用程序
  2. 插入代码(每个 阻止在一个班级)
  3. 运行applcation
  4. 使用浏览器打开网址: http://localhost:9001/Message/Test
  5. 响应是Json: {“message”:“OK!”,“success”:true}
  6. 您可以检查响应和 请参阅自定义标题:“user-agent:My Browser”

答案 1 :(得分:0)

您只能使用ApplyClientBehavior将消息检查器放在客户端。服务方还有另一种方法:

public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
  if (endpointDispatcher != null)
  {
    endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new MessageInspector());
  }
}