当UserNamePasswordValidator处理时间过长时,WCF ServiceHost崩溃

时间:2010-10-28 08:18:48

标签: c# .net wcf

我发现如果ServiceHost具有需要一段时间处理的UserNamePasswordValidator,WCF客户端可能会崩溃WCF ServiceHost。在我把它扔到微软之前,我想听听有关解决方案的任何建议。

重现的步骤是:

  1. 打开频道
  2. 调用一个需要10秒钟才能返回的API方法。
  3. 在API方法返回之前关闭通道。
  4. API方法返回。 ServiceHost崩溃。
  5. 如果UserNamePasswordValidator需要一段时间来处理(例如,2秒睡眠),则只会发生上述情况。如果UserNamePasswordValidator立即返回,则上述情况发生变化:

    1. 打开频道
    2. 调用一个需要10秒钟才能返回的API方法。
    3. 在API方法返回之前关闭通道。
    4. 关闭通道等待待处理的API方法调用。
    5. API方法返回。
    6. 频道关闭。一切都很好。
    7. 客户端代码如下:

      public static void Main(string[] args)
      {
          var binding = new NetTcpBinding(SecurityMode.TransportWithMessageCredential);
          binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
          var identity = new DnsEndpointIdentity("Dummy");
          var endpointAddress = new EndpointAddress(new Uri("net.tcp://localhost:5000/"), identity);
          var channelFactory = new ChannelFactory<IService>(binding, endpointAddress);
      
          channelFactory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
          channelFactory.Credentials.UserName.UserName = "foo";
          channelFactory.Credentials.UserName.Password = "bar";
      
          channelFactory.Open();
      
          IService service = channelFactory.CreateChannel();
      
          ThreadPool.QueueUserWorkItem(CallPingOnChannel, service);
      
          Thread.Sleep(TimeSpan.FromSeconds(1));
      
          channelFactory.Close();
      }
      
      private static void CallPingOnChannel(object state)
      {
          var result = ((state) as IService).Ping();
      }
      

      ServiceHost的设置如下:

      public static void Main(string[] args)
      {
          var serviceHost = new ServiceHost(typeof(Service), TcpBaseAddress);
          serviceHost.Description.Behaviors.Add(new ErrorHandler());
          var netTcpBinding = new NetTcpBinding(SecurityMode.TransportWithMessageCredential);
          netTcpBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Certificate;
          netTcpBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
      
          serviceHost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
          serviceHost.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new UserValidator();
      
          serviceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
          serviceHost.Credentials.ServiceCertificate.Certificate = GetCertificate();
      
          serviceHost.AddServiceEndpoint(typeof(IService), netTcpBinding, "");
      
          serviceHost.Open();
      
          Console.ReadLine();
      }
      

      UserValidator实现如下:

      public class UserValidator : UserNamePasswordValidator
      {
          public override void Validate(string userName, string password)
          {
              Thread.Sleep(TimeSpan.FromSeconds(2));
          }
      }
      

      导致主线程崩溃的未处理异常是:

      System.ServiceModel.CommunicationException: The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '10675199.02:48:05.4775807'. ---> System.IO.IOException: The read operation failed, see inner exception. ---> System.ServiceModel.CommunicationException: The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '10675199.02:48:05.4775807'. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
      

2 个答案:

答案 0 :(得分:3)

回答我自己的问题;我向微软报告了这一点,他们已经确认这是一个框架中的错误,将在即将发布的版本中修复。

链接:http://connect.microsoft.com/wcf/feedback/details/622164/wcf-servicehost-crashes-when-usernamepasswordvalidator-takes-too-long-to-process

答案 1 :(得分:0)

首先,您应该在客户端代码中捕获System.TimeOutException。

接下来,您应该考虑扩展您的客户端和服务的SendTimeoutRecieveTimeout

看看这两个链接。

SendTimeOut Property

RecieveTimeOut Property