Démarrage rapide de la résolution des problèmes WCF
Cette rubrique décrit quelques problèmes connus rencontrés par les clients lorsqu'ils développement des clients et services WCF. Si le problème que vous rencontrez n'est pas répertorié dans la liste, nous vous recommandons de configurer le traçage de votre service. Vous allez ainsi générer un fichier de suivi que vous pourrez consulter à l'aide de la visionneuse dédiée pour obtenir des informations détaillées sur les exceptions pouvant se produire au sein du service. Pour plus d’informations sur la configuration du traçage, consultez Configuring Tracing. Pour plus d’informations sur la visionneuse de fichier de traçage, consultez Service Trace Viewer Tool (SvcTraceViewer.exe).
-
Erreur HTTP 404.3 – Introuvable. Impossible d’afficher la page demandée en raison de la configuration d’extension. Si la page est un script, ajoutez un gestionnaire. Si le fichier doit être téléchargé, ajoutez un mappage MIME. Erreur détaillée InformationModule StaticFileModule.
Qu'est-ce que l'adresse de base ? Comment est-elle liée à une adresse de point de terminaison ?
Après l'installation de Windows 7 et IIS, lorsque vous tentez d'accéder à un service WCF, vous obtenez le message d'erreur suivant : Erreur HTTP 404.3 –Introuvable
Voici le message d'erreur complet :
Erreur HTTP 404.3 – Introuvable. Impossible d’afficher la page demandée en raison de la configuration d’extension. Si la page est un script, ajoutez un gestionnaire. Si le fichier doit être téléchargé, ajoutez un mappage MIME. Erreur détaillée InformationModule StaticFileModule.
Ce message d’erreur se produit lorsque l’option « Activation HTTP de Windows Communication Foundation » n’est pas explicitement définie dans le Panneau de configuration. Pour la définir, dans le Panneau de configuration, cliquez sur Programmes dans le coin inférieur gauche de la fenêtre. Cliquez sur Activer ou désactiver des fonctionnalités Windows. Développez l'élément Microsoft .NET Framework 3.5.1, puis sélectionnez Activation HTTP de Windows Communication Foundation.
Je reçois parfois une MessageSecurityException sur la deuxième demande si mon client est inactif pendant un instant après la première demande. Ce qui se passe
La deuxième demande peut échouer pour deux raisons principales : (1) la session a expiré ou (2) le serveur Web qui héberge le service est recyclé. Dans le premier cas, la session est valide jusqu’à ce que le service expire. Lorsque le service ne reçoit pas de demande du client pendant la période spécifiée dans la liaison du service (ReceiveTimeout), le service met fin à la session de sécurité. Les messages clients suivants engendrent une MessageSecurityException. Le client doit de nouveau établir une session sécurisée avec le service pour envoyer de futurs messages ou utiliser un jeton de contexte de sécurité avec état. Les jetons de contexte de sécurité avec état permettent également à une session sécurisée de survivre à un serveur Web en cours de recyclage. Pour plus d’informations sur l’utilisation de jetons de contexte de sécurité avec état dans une session sécurisée, consultez Guide pratique pour créer un jeton de contexte de sécurité pour une session sécurisée. Vous pouvez également désactiver des sessions sécurisées. Lorsque vous utilisez la liaison <wsHttpBinding>, vous pouvez affecter à la propriété establishSecurityContext
la valeur false
pour désactiver les sessions sécurisées. Pour désactiver des sessions sécurisées pour d'autres liaisons, vous devez créer une liaison personnalisée. Pour plus d’informations sur la création d’une liaison personnalisée, consultez How to: Create a Custom Binding Using the SecurityBindingElement. Avant d'appliquer chacune de ces options, vous devez comprendre les conditions de sécurité de votre application.
Mon service commence à rejeter les nouveaux clients une fois qu'environ 10 clients interagissent avec lui. Ce qui se passe
Par défaut, les services peuvent avoir uniquement 10 sessions simultanées. Par conséquent, si les liaisons de service utilisent des sessions, le service accepte les nouvelles connexions clientes jusqu'à ce qu'il atteigne ce nombre, après quoi il refuse les nouvelles connexions clientes jusqu'à ce que l'une des sessions en cours se termine. Vous pouvez prendre en charge davantage de clients de plusieurs manières. Si votre service ne requiert pas de sessions, n’utilisez pas de liaison avec session. (Pour plus d’informations, consultez Utilisation de sessions.) Une autre option consiste à augmenter la limite de session en changeant la valeur de la propriété MaxConcurrentSessions par le nombre approprié à votre situation.
Est-ce que je peux charger la configuration de mon service autrement qu'à partir du fichier de configuration de l'application WCF ?
Oui. Toutefois vous devez créer une classe ServiceHost personnalisée qui remplace la méthode ApplyConfiguration . À l'intérieur de cette méthode, vous pouvez appeler la base pour charger la configuration en premier (si vous souhaitez charger également les informations de configuration standard), mais vous pouvez également remplacer entièrement le système de chargement de la configuration. Si vous souhaitez charger la configuration à partir d’un fichier de configuration différent de celui de l’application, vous devez analyser le fichier de configuration vous-même et charger la configuration.
L'exemple de code suivant indique la manière de substituer la méthode ApplyConfiguration et de configurer directement un point de terminaison.
public class MyServiceHost : ServiceHost
{
public MyServiceHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
Console.WriteLine("MyServiceHost Constructor");
}
protected override void ApplyConfiguration()
{
string straddress = GetAddress();
Uri address = new Uri(straddress);
Binding binding = GetBinding();
base.AddServiceEndpoint(typeof(IData), binding, address);
}
string GetAddress()
{
return "http://MyMachine:7777/MyEndpointAddress/";
}
Binding GetBinding()
{
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.None;
return binding;
}
}
Mon service et mon client fonctionnent convenablement, mais je ne parviens pas à les faire fonctionner lorsque le client est sur un autre ordinateur. Que se passe-t-il ?
En fonction de l'exception, plusieurs problèmes peuvent exister :
Vous devrez peut-être remplacer les adresses de point de terminaison du client par le nom d'hôte, au lieu de « localhost ».
Vous devrez peut-être ouvrir le port vers l'application. Pour plus d’informations, consultez Firewall Instructions dans les exemples du Kit de développement logiciel.
Pour d’autres problèmes possibles, consultez la rubrique d’exemples Exécution des exemples Windows Communication Foundation.
Si votre client utilise des informations d'identification Windows et que l'exception est une SecurityNegotiationException, configurez Kerberos comme suit.
Ajoutez les informations d'identification à l'élément de point de terminaison dans le fichier App.config du client :
<endpoint address="http://MyServer:8000/MyService/" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IServiceExample" contract="IServiceExample" behaviorConfiguration="ClientCredBehavior" name="WSHttpBinding_IServiceExample"> <identity> <userPrincipalName value="name@corp.contoso.com"/> </identity> </endpoint>
Exécutez le service auto-hébergé sous le compte System ou NetworkService. Vous pouvez exécuter cette commande pour créer une fenêtre de commande sous le compte System :
at 12:36 /interactive "cmd.exe"
Hébergez le service sous IIS (Internet Information Services) qui, par défaut, utilise le compte du nom de principal du service (SPN).
Enregistrez un nouveau SPN avec le domaine à l'aide de SetSPN. Vous devez être administrateur de domaine pour effectuer cette opération.
Pour plus d’informations sur le protocole Kerberos, consultez Concepts de sécurité utilisés dans WCF et :
Lorsque je lève une FaultException<Exception> où le type est une exception, je reçois toujours un type FaultException général sur le client, et non le type générique. Que se passe-t-il ?
Il est fortement recommandé de créer votre propre type de données d'erreur personnalisé et de le déclarer comme le type de détail dans votre contrat d'erreur. La raison est que l'utilisation des types d'exceptions fournis par le système :
crée une dépendance des types qui supprime l'une des plus grandes forces des applications orientées service ;
ne peut pas dépendre d'exceptions sérialisant de manière standard (certaines, comme SecurityExceptionrisquent de pas être du tout sérialisables) ;
expose des informations d'implémentation interne aux clients. Pour plus d’informations, consultez Spécification et gestion des erreurs dans les contrats et les services.
Si vous déboguez une application, toutefois, vous pouvez sérialiser des informations sur les exceptions et les renvoyer au client à l'aide de la classe ServiceDebugBehavior .
Il semble que les opérations monodirectionnelles et demande-réponse reviennent quasiment à la même vitesse lorsque la réponse ne contient pas de données. Que se passe-t-il ?
Spécifier qu'une opération est monodirectionnelle signifie uniquement que le contrat de l'opération accepte un message d'entrée et ne renvoie pas de message de sortie. Dans WCF, tous les appels clients sont renvoyés lorsque les données sortantes ont été écrites sur le fil ou qu’une exception est levée. Les opérations monodirectionnelles fonctionnent de la même façon et elles peuvent lever si le service ne peut pas être localisé ou bloquer si le service n'est pas préparé à accepter les données du réseau. En général, dans WCF, cela provoque des appels monodirectionnels renvoyés au client plus rapidement qu’une demande-réponse ; mais toute condition qui ralentit l’envoi des données sortantes sur le réseau ralentit les opérations monodirectionnelles ainsi que les opérations demande-réponse. Pour plus d’informations, consultez Services unidirectionnel et Accès aux services à l’aide d’un client WCF.
J'utilise un certificat X.509 avec mon service et j'obtiens une System.Security.Cryptography.CryptographicException. Que se passe-t-il ?
Cela se produit couramment après avoir modifié le compte d'utilisateur sous lequel le processus de travail IIS s'exécute. Par exemple, dans Windows XP, si vous modifiez le compte d’utilisateur par défaut sous lequel Aspnet_wp.exe s’exécute en remplaçant ASPNET par un compte d’utilisateur personnalisé, vous pouvez recevoir cette erreur. Lors de l'utilisation d'une clé privée, le processus qui l'utilise aura besoin des autorisations d'accès au fichier qui stocke cette clé.
Le cas échéant, vous devez octroyer des privilèges d'accès en lecture au compte du processus pour le fichier contenant la clé privée. Par exemple, si le processus de travail IIS s'exécute sous le compte Jacques, vous devrez octroyer à Jacques un accès en lecture au fichier contenant la clé privée.
Pour plus d’informations sur la manière d’octroyer au compte d’utilisateur correct l’accès au fichier contenant la clé privée pour un certificat X.509 spécifique, consultez Guide pratique pour rendre des certificats X.509 accessibles à WCF.
J'ai remplacé les majuscules du premier paramètre d'une opération par des minuscules ; à présent, mon client lève une exception. Que se passe-t-il ?
Les valeurs des noms de paramètres dans la signature de l’opération font partie du contrat et respectent la casse. Utilisez l'attribut System.ServiceModel.MessageParameterAttribute lorsque vous devez distinguer le nom du paramètre local et les métadonnées qui décrivent l'opération pour les applications clientes.
J'utilise l'un de mes outils de suivi et j'obtiens une EndpointNotFoundException. Que se passe-t-il ?
Si vous utilisez un outil de suivi qui n’est pas le mécanisme de suivi WCF fourni par le système et que vous recevez une EndpointNotFoundException qui indique une incompatibilité du filtre d’adresse, vous devez utiliser la classe ClientViaBehavior pour diriger les messages vers l’utilitaire de suivi et faire rediriger ces messages par l’utilitaire vers l’adresse du service. La classe ClientViaBehavior altère l'en-tête d'adressage Via
pour spécifier l'adresse réseau suivante séparément du dernier destinataire, indiqué par l'en-tête d'adressage To
. Ce faisant, en revanche, ne modifiez pas l'adresse du point de terminaison, utilisée pour établir la valeur To
.
L'exemple de code suivant présente un exemple de fichier de configuration d'un client.
<endpoint
address="http://localhost:8000/MyServer/"
binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IMyContract"
behaviorConfiguration="MyClient"
contract="IMyContract"
name="WSHttpBinding_IMyContract">
</endpoint>
<behaviors>
<endpointBehaviors>
<behavior name="MyClient">
<clientVia viaUri="http://localhost:8001/MyServer/"/>
</behavior>
</endpointBehaviors>
</behaviors>
Qu'est-ce que l'adresse de base ? Comment est-elle liée à une adresse de point de terminaison ?
Une adresse de base est l'adresse racine d'une classe ServiceHost . Par défaut, si vous ajoutez une classe ServiceMetadataBehavior dans votre configuration de service, tous les points de terminaison WSDL (Web Services Description Language) que l'hôte publie sont récupérés à partir de l'adresse de base HTTP, plus toute adresse relative fournie au comportement de métadonnées, plus « ?wsdl ». Si vous connaissez bien ASP.NET et IIS, l’adresse de base équivaut au répertoire virtuel.
Partage d'un port entre un point de terminaison de service et un point de terminaison mex à l'aide de NetTcpBinding
Si vous spécifiez l'adresse de base d'un service en tant que net.tcp://MyServer:8080/MyService et ajoutez les points de terminaison suivants :
<services>
<service name="Microsoft.Samples.NetTcp.CalculatorService">
<endpoint address="calcsvc" binding ="netTcpBinding" contract="Microsoft.Samples.NetTcp.ICalculator"/>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
</services>
Et si vous modifiez un des paramètres NetTcpBinding comme illustré dans l'extrait de configuration suivant :
<bindings>
<netTcpBinding>
<binding closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="11" maxReceivedMessageSize="65536">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
</security>
</binding>
</netTcpBinding>
</bindings>
Un message d'erreur se présentant comme suit s'affiche : Exception non gérée : System.ServiceModel.AddressAlreadyInUseException : Il existe déjà un écouteur sur le point de terminaison IP 0.0.0.0:9000 Vous pouvez contourner cette erreur en spécifiant une URL complète avec un autre port pour le point de terminaison MEX comme illustré dans l'extrait de configuration suivant :
<services>
<service name="Microsoft.Samples.NetTcp.CalculatorService">
<endpoint address="calcsvc" binding ="netTcpBinding" contract="Microsoft.Samples.NetTcp.ICalculator"/>
<endpoint address="net.tcp://localhost:9001/servicemodelsamples/mex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
</services>
Lors de l'appel d'une application HTTP Web WCF à partir d'une application SOAP WCF, le service retourne l'erreur suivante : 405 Méthode non autorisée
L’appel d’une application HTTP web WCF (un service qui utilise WebHttpBinding et WebHttpBehavior) à partir d’un service WCF peut générer l’exception suivante : Unhandled Exception: System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]: The remote server returned an unexpected response: (405) Method Not Allowed.
Cette exception se produit car WCF remplace le OperationContext sortant par le OperationContext entrant. Pour résoudre ce problème, créez un OperationContextScope dans l’opération de service HTTP web WCF. Par exemple :
public string Echo(string input)
{
using (new OperationContextScope(this.InnerChannel))
{
return base.Channel.Echo(input);
}
}