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

156

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

Qu'est-ce que cette erreur et comment pourrais-je la résoudre?

Innova
la source

Réponses:

151

Vous obtenez cette erreur parce que vous laissez une exception .NET se produire du côté de votre serveur, que vous ne l'avez pas détectée et traitée, et que vous ne l'avez pas non plus convertie en erreur SOAP.

Maintenant que le côté serveur a été "bombardé", le runtime WCF a "mis en défaut" le canal - par exemple, le lien de communication entre le client et le serveur est inutilisable - après tout, il semble que votre serveur a explosé, donc vous ne pouvez pas communiquer avec plus.

Donc, ce que vous devez faire est:

  • attrapez et gérez toujours vos erreurs côté serveur - ne laissez pas les exceptions .NET voyager du serveur vers le client - enveloppez toujours celles-ci dans des erreurs SOAP interopérables. 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 dans l'état défectueux:

    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 tel est le cas, tout ce que vous pouvez faire est de vous en débarrasser et de recréer le proxy côté client, puis réessayer

marc_s
la source
11
Il semble que la même erreur puisse se produire lorsque le problème est également du côté client: par exemple, lorsque le quota de taille de message pour les messages entrants a été dépassé.
svick
6
Comment puis-je recréer le client?
Masoud
32

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

  1. Utilisez une FaultException (celle-ci n'est pas inattendue pour WCF, afin que la WCF sache que le serveur a toujours un état valide)
    au lieu de

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

    utiliser toujours

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

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

    try   
    {  
        ... some code here   
    }
    catch (Exception ex)
    {  
        throw new FaultException(ex.Message)   
    }
  2. Dites à 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 avons à faire de plus, c'est d'utiliser l'attribut [SvcErrorHandlerBehaviour]sur l'implémentation 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 plonger plus profondément dans IErrorhandler en n'utilisant pas le naked FaultException, mais FaultException<>avec un type qui fournit des informations supplémentaires, voir IErrorHandler pour un exemple détaillé.

BerndK
la source
10

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

Conseil: Dans de tels cas, l'application cliente appellera très probablement le service Web correctement lorsqu'elle sera exécutée directement sur la machine serveur sous le compte administratif dans la session RDP.

timmi4sa
la source
2

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 lorsqu'une exception est levée.

L'exception d'origine lancée aura un message d'erreur bien meilleur que ".. il est dans l'état Faulted".

Par exemple, j'obtenais cette exception de ServiceHost.Open (), mais lorsque j'ai attrapé l'exception d'origine au moment où elle a été lancée, le message d'erreur était:

Le service 'MyServiceName' n'a aucun point de terminaison d'application (non-infrastructure). Cela peut être dû au fait qu’aucun fichier de configuration n’a été trouvé pour votre application, qu’aucun élément de service correspondant au nom de service n’a été trouvé dans le fichier de configuration, ou qu’aucun point de terminaison n’a été défini dans l’élément de service.

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

Dale Wilson
la source
Dans VS2015, choisissez Déboguer → Paramètres d'exception et cochez Exceptions Common Language Runtime.
SharpC
1
Alors, pourquoi l'exception d'origine n'a-t-elle pas été donnée jusqu'à ce que vous utilisiez le débogueur Visual Studio?
Jez
2

J'ai eu le même problème en essayant de consommer le point de terminaison de 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 produit-il, mais seulement comment le gérer correctement.

J'ai eu du mal avec cela plusieurs jours de suite et j'ai finalement 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 la balise de sécurité de la même manière que dans la source, mais ce n'était pas le cas et je devrais m'en occuper manuellement. Dans mon cas, je n'avais que

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

Plus tard, j'ai vu que la partie sécurité manquait et cela 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 WCF source et dans le client, je n'avais rien de spécifique à ce sujet, ce qui était mauvais, car la valeur par défaut transferModeest Bufferedet il est important à la fois la source et le client d'être configurés dans le même façon.

ppenchev
la source
1

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 finaux sur la même adresse TCP et le même port. Dans app.config, j'avais oublié d'ajouter les deux points de terminaison, le service fonctionnait donc sur le bon port, mais avec la mauvaise interface de service.

Karsten
la source
1

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

Horev Ivan
la source
J'ai eu le même problème et je suis resté coincé sur cette question pendant un bon moment. Ce n'est probablement pas une bonne pratique d'avoir à la fois client et serveur sur la même solution. Je vous remercie!
yoosha le
1

Pour moi, le problème a été causé par le fichier de configuration généré automatiquement par l'importation du WSDL. J'ai mis à jour la liaison de basicHttpBinding vers customBinding. L'ajout d'une gestion supplémentaire des exceptions n'a pas aidé à le souligner.

Avant

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

Après

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

Dans mon cas, la raison était un certificat erroné qui n'a pas pu être chargé. Je l'ai découvert dans l'Observateur d'événements, sous Système:

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

Altumano
la source
0

Cette erreur peut également être déclenchée par votre propre ordinateur, et pas seulement par une exception non gérée. Si l'heure de votre serveur / ordinateur est décalée de trop de minutes, de nombreux services Web .NET rejetteront votre demande avec une erreur non gérée. C'est géré de leur point de vue, mais non géré de votre point de vue. Vérifiez que l'heure de l'horloge de votre serveur de réception est correcte. S'il doit être corrigé, vous devrez réinitialiser votre service ou redémarrer avant la réouverture de la chaîne.

J'ai rencontré ce problème sur un serveur où le pare-feu a bloqué la mise à jour de l'heure Internet et le serveur a cessé de fonctionner pour une raison quelconque. Tous les services Web tiers .NET sont tombés en panne 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 de notre côté même si nous avons reçu le message d'erreur Faulted State pour les futurs appels de service Web.

HBlackorby
la source
0

Le serveur abandonnera automatiquement les connexions sur lesquelles aucun message n'a été reçu pendant la durée égale au délai de réception (la valeur par défaut est de 10 minutes ). Il s'agit d'une atténuation DoS pour empêcher les clients de forcer le serveur à ouvrir des connexions pendant une durée indéfinie.

Étant donné que le serveur abandonne la connexion car elle est devenue inactive, le client obtient cette exception.

Vous pouvez contrôler la durée pendant laquelle le serveur autorise une connexion à rester inactive avant de l'abandonner en configurant le délai de réception sur la liaison du serveur. Crédit: TRVishwanath - MSFT

Vijay Rana
la source
0

Je sais que c'est un article plus ancien, 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'obtenais cette erreur.

Joshua G
la source
0

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

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

goku_da_master
la source
-2

Ce n'est pas une solution à ce problème, mais si vous rencontrez l'erreur ci-dessus avec Ektron eSync, il se peut que votre base de données soit à court d'espace disque.

Edit: En fait, ce n'est pas entièrement un problème uniquement Ektron eSync. Cela peut se produire sur n'importe quel service qui interroge une base de données complète.

Modifier: l'espace disque insuffisant ou le blocage de l'accès à un répertoire dont vous avez besoin provoquera ce problème.

Jonathan Bick
la source
Cela ne répond pas à la question. Pour critiquer ou demander des éclaircissements à un auteur, laissez un commentaire sous son message - vous pouvez toujours commenter vos propres articles, et une fois que vous avez une réputation suffisante, vous pourrez commenter n'importe quel article .
Dariusz
2
J'ai répondu à sa question "comment pourrais-je le résoudre?", Ce n'est pas de ma faute s'il ne nous a jamais donné le détail pour savoir s'il utilisait Ektron ou non. J'ai également besoin de 50 représentants pour commenter son message.
Jonathan Bick