开发者

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

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

What is this error all about, and ho开发者_运维技巧w would I go about solving it?


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


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.


As a matter of fact, if unsuccessful after following suggestions by marc_s, please keep in mind that a <security> element in server binding configuration (or lack thereof) in web.config on the server may cause this exception. For instance the server is expecting Message-level security and client is configured to None (or, if the server is not part of an Active Directory domain but the remote client host is).

Tip: In such cases the client app will most likely invoke the web service fine when executed directly on the server machine under administrative account in RDP session.


I had the same problem while trying to consume net.tcp wcf service endpoint in a http asmx service.

As I saw no one wrote specific answer WHY is this problem occurring, but only how to be handled properly.

I've been struggling with it several days in a row and finally I found out where the problem comes from in my case.

Initially I thought that when you make a reference to a service the config file will be configured regarding security tag the same way as it's in the source, but that was not the case and I should take care of it manually. In my case I had only

<netTcpBinding>
    <binding name="NetTcpBinding_IAuthenticationLoggerService"
    </binding>
</netTcpBinding>`

Later I saw that the security part is missing and it should looks like this

<netTcpBinding>
    <binding name="NetTcpBinding_IAuthenticationLoggerService" transferMode="Buffered">
      <security mode="None">
        <transport clientCredentialType="None"/>
      </security>
    </binding>
  </netTcpBinding>

The second problem in my case was that I was using transferMode="Streamed" on my source WCF service and in the client I had nothing specific about it, which was bad, because the default transferMode is Buffered and it's important on both places source and client to be configured in the same way.


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.


I had another problem, that I don't think have been mentioned in the other answers.

I have to service endpoints on the same tcp address and port. In the app.config, I had forgotten to add both endpoints, so the service was running on the correct port, but with the wrong service interface.


If you see this message in Debug from Visual Studio and solution contains WCF project. Then open this WCF project settings -> go to "WCF Options" tab -> off "Start WCF Service Host when debugging..." option


The server will automatically abort connections over which no message has been received for the duration equal to the receive timeout (default is 10 mins). This is a DoS mitigation to prevent clients from forcing the server to have connections open for an indefinite amount of time.

Since the server aborts the connection because it has gone idle, the client gets this exception.

You can control how long the server allows a connection to go idle before aborting it by configuring the receive timeout on the server's binding. Credit: T.R.Vishwanath - MSFT


For me the issue was caused by config file automatically genearted by importing the WSDL. I updated the binding to from basicHttpBinding to customBinding. Adding additional exception handling did not help pointing this out.

Before

<basicHttpBinding>
            <binding name="ServiceName">
                <security mode="Transport" />
            </binding>
        </basicHttpBinding>`

After

<customBinding>
        <binding name="ServiceName">
          <textMessageEncoding messageVersion="Soap12" />
          <httpsTransport />
        </binding>
      </customBinding>`


In my case the reason was some wrong certificate that could not be loaded. I found out about it from the Event Viewer, under System:

A fatal error occurred when attempting to access the TLS server credential private key. The error code returned from the cryptographic module is 0x8009030D. The internal error state is 10001.


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.


I know this is an older post but one thing to watch out for when you cannot change the security is to make sure that your username and password are set.

I had a service with authenticationMode as UserNameOverTransport, when the username and password were not set for the service client I would get this error.


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.


we are using MSMQ in our system, this error message came. The reason was our queue was full and we did not handle the error logging mechanism properly so we were getting the above exception instead of msmq ful. We cleared the messages then it is working fine.


For us the issue was that the website was not whitelisted, which our application needed to reach. After the site got whitelisted the error went away.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜