O objeto de comunicação, System.ServiceModel.Channels.ServiceChannel, não pode ser usado para comunicação

156

O objeto de comunicação, System.ServiceModel.Channels.ServiceChannel, não pode ser usado para comunicação porque está no estado Falha.

O que é esse erro e como eu iria resolvê-lo?

Innova
fonte

Respostas:

151

Você recebe esse erro porque deixou uma exceção .NET acontecer no lado do servidor, e não a capturou e manipulou, nem a converteu em uma falha SOAP.

Agora, como o servidor "bombardeou", o tempo de execução do WCF "causou uma falha" no canal - por exemplo, o link de comunicação entre o cliente e o servidor não pode ser usado - afinal, parece que o servidor acabou de explodir, portanto você não pode se comunicar com ele. mais isso.

Então, o que você precisa fazer é:

  • sempre identifique e lide com os erros do lado do servidor - não permita que exceções do .NET viajem do servidor para o cliente - envolva-as sempre em falhas SOAP interoperáveis. Confira a interface WCF IErrorHandler e implemente-a no lado do servidor

  • se você estiver prestes a enviar uma segunda mensagem para o seu canal do cliente, verifique se o canal não está no estado com falha:

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

    Se for, tudo o que você pode fazer é descartá-lo e recriar o proxy do lado do cliente novamente e tente novamente

marc_s
fonte
11
Parece que o mesmo erro pode ocorrer quando o problema também está no lado do cliente: por exemplo, quando a cota de tamanho de mensagem para mensagens recebidas foi excedida.
svick
6
Como posso recriar o cliente?
Masoud
32

Para impedir que o servidor caia no estado de falha, você deve garantir que nenhuma exceção não tratada seja gerada. Se o WCF vir uma exceção inesperada, não serão mais chamadas - segurança primeiro.
Duas possibilidades para evitar esse comportamento:

  1. Use uma FaultException (essa não é inesperada para o WCF, para que o WCF saiba que o servidor ainda possui um estado válido) em
    vez de

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

    use sempre

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

    talvez você possa tentar ... pegar o bloco inteiro e lançar uma FaultException em todos os casos de uma exceção

    try   
    {  
        ... some code here   
    }
    catch (Exception ex)
    {  
        throw new FaultException(ex.Message)   
    }
  2. Diga ao WCF para lidar com todas as exceções usando um Errorhandler. Isso pode ser feito de várias maneiras, escolhi uma simples usando um Atributo:
    Tudo o que precisamos fazer mais é usar o atributo [SvcErrorHandlerBehaviour]na Implementação de Serviço desejada

    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);
            }
        }
    }

Este é um exemplo fácil, você pode mergulhar mais fundo no IErrorhandler não usando nu FaultException, mas FaultException<>com um tipo que fornece informações adicionais, consulte IErrorHandler para obter um exemplo detalhado.

BerndK
fonte
10

De fato, se malsucedido após seguir as sugestões de marc_s , lembre-se de que um elemento <security> na configuração de ligação do servidor (ou na falta dela) no web.config no servidor pode causar essa exceção. Por exemplo, o servidor espera Messagesegurança de nível superior e o cliente está configurado para None(ou, se o servidor não fizer parte de um domínio do Active Directory, mas o host do cliente remoto).

Dica: Nesses casos, o aplicativo cliente provavelmente invocará o serviço da web quando executado diretamente na máquina do servidor em conta administrativa na sessão RDP.

timmi4sa
fonte
2

Para diagnosticar esse problema, execute o serviço no depurador do Visual Studio. Use o menu: Debug | Exceptions e indique que deseja interromper quando uma exceção for lançada.

A exceção original lançada terá uma mensagem de erro muito melhor do que "..está no estado de falha".

Por exemplo, eu estava recebendo essa exceção do ServiceHost.Open (), mas quando percebi a exceção original no momento em que foi lançada, a mensagem de erro foi:

O serviço 'MyServiceName' possui zero pontos de extremidade de aplicativo (sem infraestrutura). Isso pode ocorrer porque nenhum arquivo de configuração foi encontrado para o seu aplicativo ou porque nenhum elemento de serviço correspondente ao nome do serviço foi encontrado no arquivo de configuração ou porque nenhum terminal foi definido no elemento de serviço.

A correção do erro ortográfico no App.config resolveu o problema.

Dale Wilson
fonte
No VS2015, escolha Depurar → Configurações de exceção e marque Exceções do Common Language Runtime.
SharpC
1
Então, por que a exceção original não foi dada até você usar o depurador do Visual Studio?
Jez
2

Eu tive o mesmo problema ao tentar consumir o ponto de extremidade do serviço net.tcp wcf em um serviço http asmx.

Como eu vi, ninguém escreveu uma resposta específica POR QUE esse problema está ocorrendo, mas apenas como ser tratado adequadamente.

Estou lutando com isso há vários dias seguidos e finalmente descobri de onde vem o problema no meu caso.

Inicialmente, pensei que quando você fizer uma referência a um serviço, o arquivo de configuração será configurado com relação à etiqueta de segurança da mesma forma que na origem, mas não foi esse o caso e eu devo cuidar disso manualmente. No meu caso, eu tinha apenas

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

Mais tarde, vi que faltava a parte de segurança e deveria ficar assim

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

O segundo problema no meu caso foi que eu estava usando transferMode="Streamed"meu serviço WCF de origem e no cliente não tinha nada específico sobre ele, o que era ruim, porque o padrão transferModeé Bufferede é importante que ambos os locais, origem e cliente, sejam configurados da mesma maneira. maneira.

ppenchev
fonte
1

Eu tive outro problema, que acho que não foi mencionado nas outras respostas.

Eu tenho que atender pontos de extremidade no mesmo endereço e porta TCP. No app.config, esqueci-me de adicionar os dois pontos de extremidade; portanto, o serviço estava sendo executado na porta correta, mas com a interface de serviço incorreta.

Karsten
fonte
1

Se você vir esta mensagem em Debug do Visual Studio e a solução contiver o projeto WCF. Em seguida, abra as configurações deste projeto do WCF -> vá para a guia "Opções do WCF" -> desative a opção "Iniciar o host de serviço do WCF ao depurar ..."

Horev Ivan
fonte
Eu tive o mesmo problema e fiquei preso a esse assunto por um bom tempo. Provavelmente, não é uma boa prática ter cliente e servidor na mesma solução. Obrigado!
yoosha
1

Para mim, o problema foi causado pelo arquivo de configuração gerado automaticamente importando o WSDL. Atualizei a ligação de basicHttpBinding para customBinding. Adicionar manipulação de exceção adicional não ajudou a apontar isso.

Antes

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

Depois de

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

No meu caso, o motivo foi algum certificado errado que não pôde ser carregado. Eu descobri isso no Visualizador de Eventos, em Sistema:

Ocorreu um erro fatal ao tentar acessar a chave privada de credencial do servidor TLS. O código de erro retornado do módulo criptográfico é 0x8009030D. O estado do erro interno é 10001.

altumano
fonte
0

Este erro também pode ser disparado pelo seu próprio computador, e não apenas uma exceção não tratada. Se o servidor / computador tiver o tempo de inatividade por muitos minutos, muitos serviços da Web .NET rejeitarão sua solicitação com um erro não tratado. É tratado do ponto de vista deles, mas não do seu ponto de vista. Verifique se a hora do relógio do servidor de recebimento está correta. Se precisar ser corrigido, você precisará redefinir seu serviço ou reiniciar antes que o canal seja reaberto.

Tive esse problema em um servidor em que o firewall bloqueou a atualização da hora da Internet e o servidor ficou fora do ar por algum motivo. Todos os serviços da web .NET de terceiros falharam porque rejeitaram qualquer solicitação de serviço da web. Entrar no Visualizador de Eventos ajudou a identificar o problema, mas ajustar o relógio resolveu o problema. O erro estava do nosso lado, apesar de termos recebido a mensagem de erro Estado com falha para futuras chamadas de serviço da web.

HBlackorby
fonte
0

O servidor abortará automaticamente as conexões nas quais nenhuma mensagem foi recebida pela duração igual ao tempo limite de recebimento (o padrão é 10 minutos ). Esta é uma mitigação de DoS para impedir que os clientes forçam o servidor a ter conexões abertas por um período indefinido.

Como o servidor interrompe a conexão porque ficou ociosa, o cliente recebe essa exceção.

Você pode controlar por quanto tempo o servidor permite que uma conexão fique ociosa antes de interrompê-la, configurando o tempo limite de recebimento na ligação do servidor. Crédito: TRVishwanath - MSFT

Vijay Rana
fonte
0

Sei que esta é uma postagem mais antiga, mas uma coisa a observar quando você não pode alterar a segurança é garantir que seu nome de usuário e senha estejam definidos.

Eu tinha um serviço com authenticationMode como UserNameOverTransport, quando o nome de usuário e a senha não estavam definidos para o cliente do serviço, eu recebia esse erro.

Joshua G
fonte
0

Para mim, foi um problema de balanceador de carga / URL. Um serviço web atrás de um balanceador de carga chamado um outro serviço por trás do mesmo balanceador de carga usando a URL completa como: loadbalancer.mycompany.com. Alterei-o para ignorar o balanceador de carga ao chamar o segundo serviço usando em seu localhost.mycompany.comlugar.

Eu acho que havia algum tipo de problema de referência circular acontecendo com o balanceador de carga.

goku_da_master
fonte
-2

Não é uma solução para esse problema, mas se você estiver enfrentando o erro acima com o Ektron eSync, pode ser que o banco de dados esteja sem espaço em disco.

Edit: De fato, este não é um problema exclusivo do Ektron eSync. Isso pode acontecer em qualquer serviço que consulte um banco de dados completo.

Editar: falta de espaço em disco ou o bloqueio do acesso a um diretório necessário causará esse problema.

Jonathan Bick
fonte
Isso não fornece uma resposta para a pergunta. Para criticar ou solicitar esclarecimentos a um autor, deixe um comentário abaixo da postagem - você sempre pode comentar em suas próprias postagens e, quando tiver reputação suficiente , poderá comentar em qualquer post .
precisa
2
Eu respondi a sua pergunta "como eu iria resolvê-lo?", Não é minha culpa que ele nunca tenha nos dado detalhes sobre se ele estava usando Ektron ou não. Também preciso de 50 representantes para comentar em seu post.
Jonathan Bick