The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication

前端 未结 14 1593
我寻月下人不归
我寻月下人不归 2020-12-04 05:43

The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state.

相关标签:
14条回答
  • 2020-12-04 06:33

    You get this error because you let a .NET exception happen on your server side, and you didn't catch and handle it, and didn't convert it to a SOAP fault, either.

    Now since the server side "bombed" out, the WCF runtime has "faulted" the channel - e.g. the communication link between the client and the server is unusable - after all, it looks like your server just blew up, so you cannot communicate with it any more.

    So what you need to do is:

    • always catch and handle your server-side errors - do not let .NET exceptions travel from the server to the client - always wrap those into interoperable SOAP faults. Check out the WCF IErrorHandler interface and implement it on the server side

    • if you're about to send a second message onto your channel from the client, make sure the channel is not in the faulted state:

      if(client.InnerChannel.State != System.ServiceModel.CommunicationState.Faulted)
      {
         // call service - everything's fine
      }
      else
      {
         // channel faulted - re-create your client and then try again
      }
      

      If it is, all you can do is dispose of it and re-create the client side proxy again and then try again

    0 讨论(0)
  • 2020-12-04 06:34

    For me it was a load balancer/url issue. A web service behind a load balancer called another service behind the same load balancer using the full url like: loadbalancer.mycompany.com. I changed it to bypass the load balancer when calling the second service by using localhost.mycompany.com instead.

    I think there was some kind of circular reference issue going on with the load balancer.

    0 讨论(0)
  • 2020-12-04 06:36

    To diagnose this problem, run the service under the Visual Studio debugger. Use the menu: Debug|Exceptions and indicate that you want to break when an Exception is thrown.

    The original exception thrown will have a much better error message than "..it is in the Faulted state."

    For example I was getting this exception from ServiceHost.Open(), but when I caught the original exception at the time it was thrown, the error message was:

    Service 'MyServiceName' has zero application (non-infrastructure) endpoints. This might be because no configuration file was found for your application, or because no service element matching the service name could be found in the configuration file, or because no endpoints were defined in the service element.

    Fixing the spelling error in App.config solved the problem.

    0 讨论(0)
  • 2020-12-04 06:36

    Not a solution to this issue, but if you're experiencing the above error with Ektron eSync, it could be that your database has run out of disk space.

    Edit: In fact this isn't entirely an Ektron eSync only issue. This could happen on any service that querying a full database.

    Edit: Out of disk space, or blocking access to a directory that you need will cause this issue.

    0 讨论(0)
  • 2020-12-04 06:37

    To prevent the Server from fall in Fault state, you have to ensure that no unhandled exception is raised. If WCF sees an unexpected Exception, no more calls are accepted - safety first.
    Two possibilties to avoid this behaviour:

    1. Use a FaultException (this one is not unexpected for WCF, so the WCF knows that the server has still a valid state)
      instead of

      throw new Exception("Error xy in my function")  
      

      use always

      throw new FaultException("Error xy in my function")  
      

      perhaps you can try..catch the whole block and throw a FaultException in all cases of an Exception

      try   
      {  
          ... some code here   
      }
      catch (Exception ex)
      {  
          throw new FaultException(ex.Message)   
      }
      
    2. Tell WCF to handle all Exceptions using an Errorhandler. This can be done in several ways, I chose a simple one using an Attribute:
      All we have to do more, is to use the attribute [SvcErrorHandlerBehaviour] on the wanted Service Implementation

      using System;
      using System.Collections.ObjectModel;
      using System.ServiceModel;
      using System.ServiceModel.Channels;
      using System.ServiceModel.Description;
      using System.ServiceModel.Dispatcher;
      
      namespace MainService.Services
      {
          /// <summary>
          /// Provides FaultExceptions for all Methods Calls of a Service that fails with an Exception
          /// </summary>
          public class SvcErrorHandlerBehaviourAttribute : Attribute, IServiceBehavior
          {
              public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
              { } //implementation not needed
      
              public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints,
                                               BindingParameterCollection bindingParameters)
              { } //implementation not needed
      
              public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
              {
                  foreach (ChannelDispatcherBase chanDispBase in serviceHostBase.ChannelDispatchers)
                  {
                      ChannelDispatcher channelDispatcher = chanDispBase as ChannelDispatcher;
                      if (channelDispatcher == null)
                          continue;
                      channelDispatcher.ErrorHandlers.Add(new SvcErrorHandler());
                  }
              }
          }
      
          public class SvcErrorHandler: IErrorHandler
          {
              public bool HandleError(Exception error)
              {
                  //You can log th message if you want.
                  return true;
              }
      
              public void ProvideFault(Exception error, MessageVersion version, ref Message msg)
              {
                  if (error is FaultException)
                      return;
      
                  FaultException faultException = new FaultException(error.Message);
                  MessageFault messageFault = faultException.CreateMessageFault();
                  msg = Message.CreateMessage(version, messageFault, faultException.Action);
              }
          }
      }
      

    This is an easy example, you can dive deeper into IErrorhandler by not using the naked FaultException, but a FaultException<> with a type that provides additional info see IErrorHandler for an detailed example.

    0 讨论(0)
  • 2020-12-04 06:42

    This error can be triggered by your own computer too, and not just an unhandled exception. If your server/computer has its clock time off by too many minutes, many .NET web services will reject your request with an unhandled error. It's handled from their point of view, but unhandled from your point. Check to make sure your receiving server's clock time is correct. If it needs to be fixed, you'll have to reset your service or reboot before the channel reopens.

    I experienced this issue on a server where the firewall blocked the Internet time update, and the server got off time for some reason. All the 3rd party .NET web services went into fault because they rejected any web service request. Digging into the Event Viewer helped identify the problem, but adjusting the clock solved it. The error was on our end even though we received the Faulted State error message for future web service calls.

    0 讨论(0)
提交回复
热议问题