使用 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 端点