Réponses:
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
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:
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)
}
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é.
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 Message
sé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.
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.
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 transferMode
est Buffered
et il est important à la fois la source et le client d'être configurés dans le même façon.
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.
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 ..."
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>`
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.
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.
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
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.
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.com
place.
Je pense qu'il y avait une sorte de problème de référence circulaire avec l'équilibreur de charge.
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.