使用 IErrorHandler 和 TCP Message Security 会导致超时

Posted

技术标签:

【中文标题】使用 IErrorHandler 和 TCP Message Security 会导致超时【英文标题】:Using IErrorHandler and TCP Message Security causes a timeout 【发布时间】:2011-04-08 17:28:42 【问题描述】:

我有一个带有自定义 IServiceBehavior 的 WCF 服务,用于在客户端返回特定故障。当我使用 TCP Message Security 启用此代码时,我会收到服务超时。

您可以在下面看到重现错误的完整客户端和服务器代码。

服务器代码:

使用系统; 使用 System.Collections.Generic; 使用 System.Linq; 使用 System.Text; 使用 System.ServiceModel; 使用 System.ServiceModel.Description; 使用 System.ServiceModel.Dispatcher; 使用 System.ServiceModel.Channels; 命名空间 TestWCFServer 课堂节目 静态无效主要(字符串 [] 参数) Console.WriteLine("服务器"); NetTcpBinding 绑定 = new NetTcpBinding(); binding.Security.Mode = SecurityMode.Message; //如果你删除这一行,代码就可以工作了!!!!!! uri地址 = new Uri("net.tcp://localhost:8184/"); // 创建服务主机。 使用(ServiceHost 主机 = 新 ServiceHost(typeof(HelloWorldService))) host.AddServiceEndpoint(typeof(IHelloWorldService), 绑定, 地址); host.Description.Behaviors.Add(new MyErrorhandlerBehavior()); 主机.打开(); Console.WriteLine("服务在 0 准备就绪", address); Console.WriteLine("按下停止服务。"); Console.ReadLine(); // 关闭服务主机。 主机.关闭(); [服务合同] 公共接口 IHelloWorldService [运营合同] 字符串 SayHello(字符串名称); 公共类 HelloWorldService : IHelloWorldService 公共字符串 SayHello(字符串名称) 如果(名称 == 空) 抛出新的 ArgumentNullException("name"); return string.Format("Hello, 0", name); 类 MyErrorhandlerBehavior : IServiceBehavior, IErrorHandler #region IServiceBahvior public void AddBindingParameters(ServiceDescription serviceDescription,ServiceHostBase serviceHostBase,System.Collections.ObjectModel.Collection 端点,BindingParameterCollection bindingParameters) public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) foreach(serviceHostBase.ChannelDispatchers 中的 ChannelDispatcher chanDisp) chanDisp.ErrorHandlers.Add(this); 公共无效验证(ServiceDescription serviceDescription,ServiceHostBase serviceHostBase) #endregion #region IErrorHandler 成员 公共布尔句柄错误(异常错误) 返回真; 公共无效提供故障(异常错误,消息版本版本,参考消息消息) FaultException fe = new FaultException(error.Message); MessageFault 故障 = fe.CreateMessageFault(); msg = Message.CreateMessage(ver, fault, "net.tcp://localhost:8184/fault"); #endregion

客户端代码:

使用系统; 使用 System.Collections.Generic; 使用 System.Linq; 使用 System.Text; 使用 System.ServiceModel; 使用 System.ServiceModel.Channels; 使用 System.ServiceModel.Description; 使用 System.ServiceModel.Dispatcher; 命名空间 TestWCFClient 课堂节目 静态无效主要(字符串 [] 参数) Console.WriteLine("客户"); 尝试 NetTcpBinding 绑定 = new NetTcpBinding(); binding.Security.Mode = SecurityMode.Message; //如果你删除这一行,代码就可以工作了!!!!!! uri地址 = new Uri("net.tcp://localhost:8184/"); EndpointAddress 端点 = new EndpointAddress(address); HelloWorldServiceClient 客户端 = 新 HelloWorldServiceClient(绑定,端点); Console.WriteLine("使用有效参数调用客户端..."); Console.WriteLine(client.SayHello("Davide")); Console.WriteLine("OK"); Console.WriteLine("使用无效参数调用客户端..."); Console.WriteLine(client.SayHello(null)); //当Security设置为Message时,这个调用会导致超时 Console.WriteLine("OK"); 捕捉(例外前) Console.WriteLine(ex.Message); Console.WriteLine("回车退出"); Console.ReadLine(); [服务合同] 公共接口 IHelloWorldService [运营合同] 字符串 SayHello(字符串名称); 类 HelloWorldServiceClient : System.ServiceModel.ClientBase, IHelloWorldService 公共 HelloWorldServiceClient(System.ServiceModel.Channels.Binding 绑定,System.ServiceModel.EndpointAddress 地址): 基地(绑定,地址) 公共字符串 SayHello(字符串名称) 返回 base.Channel.SayHello(name);

如果我删除客户端和服务器上的 binding.Security.Mode = SecurityMode.Message; 行,异常被正确翻译,客户端可以毫无问题地看到它。

在 WCF 日志中,我看到以下消息: 没有为具有“net.tcp://localhost:8184/fault”操作的消息指定签名消息部分。 安全协议无法保护传出消息。

关于如何解决这个问题的任何想法?似乎我必须对错误消息进行签名/加密,但我不知道如何... 如果我使用传输安全,则代码按预期工作。

谢谢!

【问题讨论】:

【参考方案1】:

回复可能有点晚,但我遇到了同样的问题,我想通了:

您需要在接口方法上定义FaultContract 以及OperationContract。看看here。

您的错误合约对象也需要与 Action 命名空间具有相同的命名空间。

太痛苦了,但终于想通了,现在可以工作了。

【讨论】:

谢谢,你是对的。就我而言,问题是名称空间。我也可以将其设置为 null 以不每次都重复命名空间。查看我的回复...【参考方案2】:

就我而言,问题出在命名空间中。我已经用这个替换了 ProvideFault 方法:

public void ProvideFault(Exception error,MessageVersion ver, ref Message     

        FaultException fe = new FaultException(error.Message);
        MessageFault fault = fe.CreateMessageFault();
        msg = Message.CreateMessage(ver, fault, null);

注意null 参数。

还要考虑使用错误的命名空间,异常没有正确序列化。

【讨论】:

谢谢。希望其他人不必经历我们所经历的痛苦!

以上是关于使用 IErrorHandler 和 TCP Message Security 会导致超时的主要内容,如果未能解决你的问题,请参考以下文章

WCF IErrorHandler 将 FaultException 返回给 SOAP,将 WebHttpException 返回给 POX 和 Json 端点

利用Attribute和IErrorHandler处理WCF全局异常

IErrorHandler

WCF错误处理:一刀切——IErrorHandler

WCF错误协定声明

WCF自定义错误处理(IErrorHandler接口的用法)