Envoi et réception des erreurs

Les erreurs SOAP acheminent des informations de condition d'erreur d'un service à un client et, dans le cas duplex, d'un client à un service d'une manière interopérable. En général un service définit le contenu des erreurs personnalisées et spécifie quelles opérations peuvent les retourner. (Pour plus d’informations, consultez Définition et spécification des erreurs.) Cette rubrique explique comment un service ou un client duplex peut envoyer ces erreurs lorsque la condition d’erreur correspondante s’est produite et comment une application cliente ou de service gère ces erreurs. Pour obtenir une vue d’ensemble de la gestion des erreurs dans les applications Windows Communication Foundation (WCF), consultez Spécification et gestion des erreurs dans les contrats et services.

Envoi d'erreurs SOAP

Les erreurs SOAP déclarées sont celles dans lesquelles une opération contient un System.ServiceModel.FaultContractAttribute qui spécifie un type d'erreur SOAP personnalisé. Les erreurs SOAP non déclarées sont celles qui ne sont pas spécifiées dans le contrat d'une opération.

Envoi d'erreurs déclarées

Pour envoyer une erreur SOAP déclarée, détectez la condition d'erreur pour laquelle l'erreur SOAP est appropriée et levez une nouvelle System.ServiceModel.FaultException<TDetail> où le paramètre de type est un nouvel objet du type spécifié dans le FaultContractAttribute pour cette opération. L'exemple de code suivant illustre l'utilisation de FaultContractAttribute pour spécifier que l'opération SampleMethod peut retourner une erreur SOAP avec le type de détail GreetingFault.

[OperationContract]
[FaultContractAttribute(
  typeof(GreetingFault),
  Action="http://www.contoso.com/GreetingFault",
  ProtectionLevel=ProtectionLevel.EncryptAndSign
  )]
string SampleMethod(string msg);
<OperationContract, FaultContractAttribute(GetType(GreetingFault), Action:="http://www.contoso.com/GreetingFault", ProtectionLevel:=ProtectionLevel.EncryptAndSign)> _
Function SampleMethod(ByVal msg As String) As String

Pour acheminer les informations sur l'erreur GreetingFault au client, interceptez la condition d'erreur appropriée et levez une nouvelle System.ServiceModel.FaultException<TDetail> de type GreetingFault avec un nouvel objet GreetingFault comme argument, comme dans l'exemple de code suivant. Si le client est une application cliente WCF, il subit cette erreur en tant qu’exception managée où le type est System.ServiceModel.FaultException<TDetail> de type GreetingFault.

throw new FaultException<GreetingFault>(new GreetingFault("A Greeting error occurred. You said: " + msg));
    Throw New FaultException(Of GreetingFault)(New GreetingFault("A Greeting error occurred. You said: " & msg))
End If

Envoi d'erreurs non déclarées

L’envoi d’erreurs non déclarées peut être très utile pour diagnostiquer et déboguer rapidement des problèmes dans les applications WCF, mais son utilité en tant qu’outil de débogage est limitée. Plus généralement, lors du débogage il est recommandé d'utiliser la propriété ServiceDebugBehavior.IncludeExceptionDetailInFaults. Lorsque vous définissez cette valeur à « true », les clients rencontrent des erreurs telles que des exceptions FaultException<TDetail> de type ExceptionDetail.

Important

Étant donné que les exceptions managées peuvent exposer des informations d’application internes, affecter à ServiceBehaviorAttribute.IncludeExceptionDetailInFaults ou à ServiceDebugBehavior.IncludeExceptionDetailInFaults la valeur true peut autoriser les clients WCF à obtenir des informations sur les exceptions d’opération de service internes, y compris des informations personnellement identifiables ou autres informations sensibles.

Par conséquent, l'affectation de la valeur ServiceBehaviorAttribute.IncludeExceptionDetailInFaults à ServiceDebugBehavior.IncludeExceptionDetailInFaults ou true est uniquement recommandée comme une façon de déboguer temporairement une application de service. De plus, le WSDL pour une méthode qui retourne des exceptions managées non prises en charge de cette façon ne contient pas le contrat pour le FaultException<TDetail> de type ExceptionDetail. Les clients doivent attendre une erreur SOAP inconnue (retournée aux clients WCF en tant qu’objets System.ServiceModel.FaultException) pour obtenir correctement les informations de débogage.

Pour envoyer une erreur SOAP non déclarée, levez un objet System.ServiceModel.FaultException (autrement dit, pas le type générique FaultException<TDetail>) et passez la chaîne au constructeur. Cette exception est exposée aux applications clientes WCF en tant qu’exception System.ServiceModel.FaultException levée où la chaîne est disponible en appelant la méthode FaultException<TDetail>.ToString.

Notes

Si vous déclarez une erreur SOAP de type chaîne et que vous la levez ensuite dans votre service en tant que FaultException<TDetail> où le paramètre de type est un System.String, la valeur de chaîne est assignée à la propriété FaultException<TDetail>.Detail et n'est pas disponible à partir de FaultException<TDetail>.ToString.

Gestion des erreurs

Sur les clients WCF, les erreurs SOAP qui se produisent pendant la communication et qui concernent les applications clientes sont levées en tant qu’exceptions managées. Bien que de nombreuses exceptions puissent se produire durant l’exécution d’un programme, les applications qui utilisent le modèle de programmation WCF peuvent s’attendre à gérer des exceptions des deux types suivants suite à la communication.

Les objets TimeoutException sont levés lorsqu'une opération dépasse le délai d'attente spécifié.

Les objets CommunicationException sont levés lorsqu'il existe une condition d'erreur de communication récupérable sur le service ou le client.

La classe CommunicationException a deux types dérivés importants, FaultException et le type FaultException<TDetail> générique.

Les exceptions FaultException sont levées lorsqu'un écouteur reçoit une erreur inattendue ou qui n'est spécifiée dans le contrat d'opération ; habituellement, cela se produit lorsque l'application est déboguée et que le service a la propriété ServiceDebugBehavior.IncludeExceptionDetailInFaults définie à true.

Les exceptions FaultException<TDetail> sont levées sur le client lorsqu'une erreur spécifiée dans le contrat d'opération est reçue en réponse à une opération bidirectionnelle (autrement dit, une méthode avec un attribut OperationContractAttribute ayant la valeur IsOneWay affectée à la propriété false).

Notes

Lorsqu’un service WCF a la propriété ServiceBehaviorAttribute.IncludeExceptionDetailInFaults ou ServiceDebugBehavior.IncludeExceptionDetailInFaults définie sur true, le client subit l’erreur en tant que FaultException<TDetail> non déclaré de type ExceptionDetail. Les clients peuvent intercepter cette erreur spécifique ou gérer l'erreur dans un bloc catch pour FaultException.

En général, seules les exceptions FaultException<TDetail>, TimeoutException et CommunicationException sont dignes d'intérêt pour les clients et les services.

Notes

D'autres exceptions, bien sûr, se produisent. Les exceptions inattendues incluent des défaillances catastrophiques telles que System.OutOfMemoryException ; en général, les applications ne doivent pas intercepter de telles méthodes.

Interception des exceptions dans l'ordre correct

Étant donné que FaultException<TDetail> dérive de FaultException et que FaultException dérive de CommunicationException, il est important d'intercepter ces exceptions dans l'ordre approprié. Si, par exemple, vous avez un bloc try/catch dans lequel vous interceptez d'abord CommunicationException, toutes les erreurs SOAP spécifiées et non spécifiées sont gérées à cet emplacement ; les blocs catch suivants destinés à gérer une exception FaultException<TDetail> personnalisée ne sont jamais appelés.

Souvenez-vous qu'une opération peut retourner une quantité d'erreurs spécifiées quelconque. Chaque erreur est un type unique et doit être gérée séparément.

Gestion des exceptions lors de la fermeture du canal

Une grande partie de la discussion précédente traite des erreurs envoyées durant le traitement des messages de l’application, autrement dit des messages envoyés explicitement par le client lorsque l’application cliente appelle des opérations sur l'objet client WCF.

Même avec les objets locaux, l'élimination de l'objet peut déclencher ou masquer des exceptions qui se produisent pendant le processus de recyclage. Quelque chose de semblable peut se produire lorsque vous utilisez des objets clients WCF. Lorsque vous appelez des opérations, vous envoyez des messages sur une connexion établie. La fermeture du canal peut lever des exceptions si la connexion ne peut pas être fermée proprement ou si elle est déjà fermée, même si toutes les opérations ont été retournées correctement.

En général, les canaux d'objets clients sont fermés dans les cas suivants :

  • Lorsque l’objet client WCF est recyclé.

  • Lorsque l'application cliente appelle ClientBase<TChannel>.Close.

  • Lorsque l'application cliente appelle ICommunicationObject.Close.

  • Lorsque l'application cliente appelle une opération qui est une opération de fin pour une session.

Dans tous les cas, la fermeture du canal fait en sorte que celui-ci commence à fermer tous les canaux sous-jacents qui peuvent envoyer des messages pour prendre en charge la fonctionnalité complexe au niveau application. Par exemple, lorsqu’un contrat requiert des sessions, une liaison tente d’établir une session en échangeant des messages avec le canal de service jusqu’à ce qu’une session soit établie. Lorsque le canal est fermé, le canal de session sous-jacent signale au service que la session est terminée. Dans ce cas, si le canal a déjà abandonné, est déjà fermé ou est inutilisable (par exemple, lorsqu'un câble réseau est débranché), le canal client ne peut pas signaler au canal de service que la session est terminée et une exception peut être déclenchée.

Abandon du canal si nécessaire

La fermeture du canal pouvant également lever des exceptions, en plus d'intercepter les exceptions dans l'ordre correct il est important d'abandonner le canal utilisé pour effectuer l'appel dans le bloc catch.

Si l'erreur achemine des informations d'erreur spécifiques à une opération et qu'il est encore possible que d'autres puissent l'utiliser, il n'est pas nécessaire d'abandonner le canal (bien que ces cas soient rares). Dans tous les autres cas, il est recommandé d'abandonner le canal. Pour obtenir un exemple illustrant tous ces points, consultez Exceptions attendues.

L'exemple de code suivant indique comment gérer des exceptions SOAP dans une application cliente de base, y compris une erreur déclarée et une erreur non déclarée.

Notes

Cet exemple de code n'utilise pas la construction using. La fermeture des canaux pouvant lever des exceptions, il est recommandé que les applications créent tout d’abord un client WCF, puis ouvrent, utilisent et ferment le client WCF dans le même bloc try. Pour plus d’informations, consultez Vue d’ensemble du client WCF et Utiliser Close et Abort pour libérer des ressources client WCF.

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Microsoft.WCF.Documentation;

public class Client
{
  public static void Main()
  {
    // Picks up configuration from the config file.
    SampleServiceClient wcfClient = new SampleServiceClient();
    try
    {
      // Making calls.
      Console.WriteLine("Enter the greeting to send: ");
      string greeting = Console.ReadLine();
      Console.WriteLine("The service responded: " + wcfClient.SampleMethod(greeting));

      Console.WriteLine("Press ENTER to exit:");
      Console.ReadLine();

      // Done with service.
      wcfClient.Close();
      Console.WriteLine("Done!");
    }
    catch (TimeoutException timeProblem)
    {
      Console.WriteLine("The service operation timed out. " + timeProblem.Message);
      Console.ReadLine();
      wcfClient.Abort();
    }
    catch (FaultException<GreetingFault> greetingFault)
    {
      Console.WriteLine(greetingFault.Detail.Message);
      Console.ReadLine();
      wcfClient.Abort();
    }
    catch (FaultException unknownFault)
    {
      Console.WriteLine("An unknown exception was received. " + unknownFault.Message);
      Console.ReadLine();
      wcfClient.Abort();
    }
    catch (CommunicationException commProblem)
    {
      Console.WriteLine("There was a communication problem. " + commProblem.Message + commProblem.StackTrace);
      Console.ReadLine();
      wcfClient.Abort();
    }
  }
}

Imports System.ServiceModel
Imports System.ServiceModel.Channels
Imports Microsoft.WCF.Documentation

Public Class Client
    Public Shared Sub Main()
        ' Picks up configuration from the config file.
        Dim wcfClient As New SampleServiceClient()
        Try
            ' Making calls.
            Console.WriteLine("Enter the greeting to send: ")
            Dim greeting As String = Console.ReadLine()
            Console.WriteLine("The service responded: " & wcfClient.SampleMethod(greeting))

            Console.WriteLine("Press ENTER to exit:")
            Console.ReadLine()

            ' Done with service. 
            wcfClient.Close()
            Console.WriteLine("Done!")
        Catch timeProblem As TimeoutException
            Console.WriteLine("The service operation timed out. " & timeProblem.Message)
            Console.ReadLine()
            wcfClient.Abort()
        Catch greetingFault As FaultException(Of GreetingFault)
            Console.WriteLine(greetingFault.Detail.Message)
            Console.ReadLine()
            wcfClient.Abort()
        Catch unknownFault As FaultException
            Console.WriteLine("An unknown exception was received. " & unknownFault.Message)
            Console.ReadLine()
            wcfClient.Abort()
        Catch commProblem As CommunicationException
            Console.WriteLine("There was a communication problem. " & commProblem.Message + commProblem.StackTrace)
            Console.ReadLine()
            wcfClient.Abort()
        End Try
    End Sub
End Class

Voir aussi