web-dev-qa-db-fra.com

L'objet de communication, System.ServiceModel.Channels.ServiceChannel, ne peut pas être utilisé pour la communication.

L'objet de communication, System.ServiceModel.Channels.ServiceChannel, ne peut pas être utilisé pour la communication car il est à l'état Faulted. 

En quoi consiste cette erreur et comment pourrais-je résoudre le problème?

132
Innova

Vous obtenez cette erreur parce que vous avez laissé une exception .NET se produire côté serveur, que vous ne l'avez ni interceptée ni traitée, ni convertie en une erreur SOAP.

Maintenant, depuis que le serveur est "bombardé", le moteur de traitement WCF a "provoqué" le canal - par exemple. le lien de communication entre le client et le serveur est inutilisable. Après tout, il semble que votre serveur ait explosé, vous ne pouvez donc plus communiquer avec lui.

Donc, ce que vous devez faire est:

  • always détecte et gère vos erreurs côté serveur - ne pas laisser les exceptions .NET se déplacer du serveur au client - always les encapsuler dans des défauts interopérables SOAP. Découvrez l'interface WCF IErrorHandler et implémentez-la côté serveur

  • si vous êtes sur le point d'envoyer un deuxième message sur votre canal à partir du client, assurez-vous que le canal n'est pas à l'état défaillant:

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

    Si c'est le cas, tout ce que vous pouvez faire est de vous en débarrasser, de recréer le proxy côté client à nouveau, puis de réessayer.

128
marc_s

Pour empêcher le serveur de tomber en état de panne, vous devez vous assurer qu'aucune exception non gérée n'est générée. Si WCF constate une exception inattendue, aucun autre appel n'est accepté - la sécurité d'abord.
Deux possibilités pour éviter ce comportement: 

  1. Utilisez une exception FaultException (celle-ci n'étant pas inattendue pour WCF, le WCF sait donc que le serveur a toujours un état valide)
    au lieu de 

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

    toujours utiliser 

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

    peut-être que vous pouvez essayer..catch tout le bloc et lancer une FaultException dans tous les cas d'une exception

    try   
    {  
        ... some code here   
    }
    catch (Exception ex)
    {  
        throw new FaultException(ex.Message)   
    }
    
  2. Indiquez à WCF de gérer toutes les exceptions à l'aide d'un gestionnaire d'erreur. Cela peut être fait de plusieurs manières, j'ai choisi une simple en utilisant un attribut:
    Tout ce que nous devons faire, c’est d’utiliser l’attribut [SvcErrorHandlerBehaviour] sur la mise en oeuvre de service souhaitée

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

Ceci est un exemple simple, vous pouvez approfondir IErrorhandler en n'utilisant pas la variable nue FaultException, mais un FaultException<> avec un type fournissant des informations supplémentaires Voir IErrorHandler pour un exemple détaillé.

26
BerndK

Attachez à l'événement faulted pour comprendre pourquoi et quand l'erreur s'est produite.

Edit: Il serait également utile que vous publiiez des informations supplémentaires sur ce que vous faites.

7
flayn

En fait, en cas d'échec après avoir suivi les suggestions de marc_s, gardez à l'esprit qu'un élément <security> dans la configuration de liaison de serveur (ou son absence) dans web.config sur le serveur peut provoquer cette exception. Par exemple, le serveur attend une sécurité de niveau Message et le client est configuré sur None (ou, si le serveur ne fait pas partie d'un domaine Active Directory mais que l'hôte du client distant l'est).

Conseil: Dans de tels cas, l'application client invoquera probablement l'amende du service Web lorsqu'elle sera exécutée directement sur la machine serveur sous un compte administratif dans une session RDP.

7
timmi4sa

Pour diagnostiquer ce problème, exécutez le service sous le débogueur Visual Studio. Utilisez le menu: Déboguer | Exceptions et indiquez que vous souhaitez interrompre une Exception. 

L'exception originale générée aura un message d'erreur bien meilleur que "..il est à l'état Faulted". 

Par exemple, je recevais cette exception de ServiceHost.Open (), mais lorsque j'ai attrapé l'exception d'origine au moment de son lancement, le message d'erreur était le suivant:

Le service 'MyServiceName' n'a aucune application (non infrastructure) points finaux. Cela peut être dû au fait qu'aucun fichier de configuration n'a été trouvé pour votre application, ou parce qu'aucun élément de service ne correspond au nom de service peut être trouvé dans le fichier de configuration, ou parce que non les points de terminaison ont été définis dans l'élément de service.

La correction de l'erreur d'orthographe dans App.config a résolu le problème.

2
Dale Wilson

J'ai un client Web qui se connecte au service Windows via WCF . Mon application Web génère la même erreur

L'objet de communication System.ServiceModel.Channels.ServiceChannel ne peut pas être utilisé pour la communication car il est à l'état Faulted J'ai activé le traçage WCF, ce qui ne m'a pas beaucoup aidé . Enfin, le redémarrage du service Windows l'a résolu et je n'ai toujours aucune idée de la cause. le dépannage doit donc, comme toujours, commencer par un point simple. C'est un bon exemple. si quelqu'un a un problème similaire, essayez de redémarrer le service.

2
yantaq

J'ai eu un autre problème, que je ne pense pas avoir été mentionné dans les autres réponses.

Je dois desservir les points de terminaison sur la même adresse TCP et le même port. Dans le fichier app.config, j'avais oublié d'ajouter les deux points de terminaison. Le service s'exécutait donc sur le bon port, mais avec la mauvaise interface de service.

1
Karsten

J'ai eu le même problème en essayant de consommer le noeud final du service net.tcp wcf dans un service http asmx. 

Comme je l'ai vu, personne n'a écrit de réponse spécifique POURQUOI ce problème se pose-t-il, mais seulement comment être traité correctement.

Cela fait plusieurs jours que je me bats avec elle et finalement j'ai découvert d'où venait le problème dans mon cas.

Au départ, je pensais que lorsque vous faites référence à un service, le fichier de configuration sera configuré en ce qui concerne les balises de sécurité de la même manière que dans le source, mais ce n’était pas le cas et je devrais m'en occuper manuellement . cas je n'avais que

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

Plus tard, j'ai vu que la partie sécurité manquait et qu'elle devrait ressembler à ceci

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

Le deuxième problème dans mon cas était que j'utilisais transferMode="Streamed" sur mon service source WCF et que je n'avais rien de précis à ce sujet, ce qui était mauvais, car la valeur par défaut transferMode est Buffered et qu'il est important que le client source et le lieu soient configurés de la même manière.

1
ppenchev

Si vous voyez ce message dans Debug à partir de Visual Studio et que la solution contient le projet WCF ..__, ouvrez ensuite les paramètres de ce projet WCF -> allez à l'onglet "Options WCF" -> désactivez l'option "Démarrer l'hôte de service WCF lors du débogage ..."

1
Horev Ivan

Pour moi, c'était un problème d'équilibrage de charge/url. Un service Web situé derrière un équilibreur de charge a appelé un autre service situé derrière le même équilibreur de charge en utilisant l'URL complète telle que: loadbalancer.mycompany.com. Je l'ai modifié pour contourner l'équilibreur de charge lors de l'appel du deuxième service en utilisant localhost.mycompany.com à la place.

Je pense qu'il y avait une sorte de problème de référence circulaire en cours avec l'équilibreur de charge.

0
goku_da_master

Dans mon cas, la raison était un mauvais certificat qui ne pouvait pas être chargé. Je l'ai découvert dans l'observateur d'événements, sous Système:

Une erreur fatale s'est produite lors d'une tentative d'accès au serveur TLS clé privée d'identification. Le code d'erreur renvoyé par le cryptographique le module est 0x8009030D. L'état d'erreur interne est 10001.

0
altumano

Cette erreur peut également être déclenchée par votre propre ordinateur, et pas seulement par une exception non gérée. Si le temps d’horloge de votre serveur/ordinateur est trop long, de nombreux services Web .NET rejetteront votre demande avec une erreur non gérée. C'est traité de leur point de vue, mais non traité de votre point de vue. Assurez-vous que l'heure du serveur de réception est correcte. S'il doit être corrigé, vous devrez réinitialiser votre service ou redémarrer avant la réouverture du canal.

J'ai rencontré ce problème sur un serveur où le pare-feu bloquait la mise à jour de l'heure Internet et le serveur avait arrêté l'heure pour une raison quelconque. Tous les services Web tiers .NET ont eu des problèmes car ils ont rejeté toute demande de service Web. Creuser dans l'observateur d'événements a aidé à identifier le problème, mais l'ajustement de l'horloge l'a résolu. L'erreur était commise alors que nous avions reçu le message d'erreur Faulted State pour les futurs appels de service Web.

0
HBlackorby

Je sais que ceci est un ancien billet, mais une chose à surveiller lorsque vous ne pouvez pas modifier la sécurité est de vous assurer que votre nom d'utilisateur et votre mot de passe sont définis.

J'avais un service avec authenticationMode comme UserNameOverTransport, lorsque le nom d'utilisateur et le mot de passe n'étaient pas définis pour le client de service, j'obtiendrais cette erreur.

0
Joshua G

Le serveur abandonnera automatiquement les connexions pour lesquelles aucun message n'a été reçu pendant une durée égale à la temporisation de réception ( la valeur par défaut est 10 minutes ). Il s'agit d'une limitation du déni de service visant à empêcher les clients de forcer le serveur à ouvrir des connexions pour une durée indéterminée.

Étant donné que le serveur interrompt la connexion car il est devenu inactif, le client obtient cette exception. 

Vous pouvez contrôler le temps pendant lequel le serveur laisse une connexion inactive avant de l'abandonner en configurant le délai de réception sur la liaison du serveur . Credit: T.R.Vishwanath - MSFT

0
Vijay Rana