Partager via


Gestion des exceptions et des erreurs

Les exceptions sont utilisées pour communiquer des erreurs localement dans le service ou l’implémentation du client. Les fautes, d'autre part, sont utilisées pour communiquer des erreurs à travers les frontières des services, comme du serveur au client ou inversement. En plus des erreurs, les canaux de transport utilisent souvent des mécanismes spécifiques au transport pour communiquer les erreurs au niveau du transport. Par exemple, le transport HTTP utilise des codes d’état tels que 404 pour communiquer une URL de point de terminaison non existante (il n’existe aucun point de terminaison pour renvoyer une erreur). Ce document se compose de trois sections qui fournissent des conseils aux auteurs de canaux personnalisés. La première section fournit des conseils sur le moment et la façon de définir et de lever des exceptions. La deuxième section fournir des indications sur la génération et la consommation des erreurs. La troisième section explique comment fournir des informations de trace pour aider l’utilisateur de votre canal personnalisé à résoudre les problèmes liés aux applications en cours d’exécution.

Exceptions

Il existe deux éléments à garder à l’esprit lors de la levée d’une exception : tout d’abord, il doit s’agir d’un type qui permet aux utilisateurs d’écrire du code correct qui peut réagir de manière appropriée à l’exception. Deuxièmement, il doit fournir suffisamment d’informations à l’utilisateur pour comprendre ce qui s’est passé, l’impact sur l’échec et comment le corriger. Les sections suivantes fournissent des conseils sur les types d’exceptions et les messages pour les canaux Windows Communication Foundation (WCF). Il existe également des conseils généraux sur les exceptions dans .NET dans le document Recommandations de conception pour les exceptions.

Types d’exceptions

Toutes les exceptions levées par les canaux doivent être soit System.TimeoutException, System.ServiceModel.CommunicationException, soit un type dérivé de CommunicationException. (Des exceptions telles que ObjectDisposedException celles-ci peuvent également être levées, mais uniquement pour indiquer que le code appelant a mal utilisé le canal. Si un canal est utilisé correctement, il ne doit lever que les exceptions données.) WCF fournit sept types d’exceptions qui dérivent CommunicationException et sont conçus pour être utilisés par les canaux. Il existe d’autres CommunicationExceptionexceptions dérivées conçues pour être utilisées par d’autres parties du système. Ces types d’exceptions sont les suivants :

Type d’exception Sens Contenu d’exception interne Planification d’une stratégie de récupération
AddressAlreadyInUseException L’adresse de point de terminaison spécifiée pour l’écoute est déjà utilisée. S’il est présent, fournit plus de détails sur l’erreur de transport qui a provoqué cette exception. Par exemple. PipeException, HttpListenerException, ou SocketException. Essayez une autre adresse.
AddressAccessDeniedException Le processus n’est pas autorisé à accéder à l’adresse de point de terminaison spécifiée pour l’écoute. S’il est présent, fournit plus de détails sur l’erreur de transport qui a provoqué cette exception. Par exemple, PipeException ou HttpListenerException. Essayez avec différentes informations d’identification.
CommunicationObjectFaultedException Le ICommunicationObject utilisé est en état de défaut (pour plus d'informations, consultez Comprendre les changements d'état). Notez que lorsqu’un objet avec plusieurs appels en attente passe à l’état défectueux, un seul appel lève une exception liée à l’échec et le reste des appels lève un CommunicationObjectFaultedException. Cette exception est généralement levée, car une application ignore une exception et tente d’utiliser un objet déjà défectueux, éventuellement sur un thread autre que celui qui a intercepté l’exception d’origine. Le cas échéant, fournit des détails à propos de l'exception interne. Créez un objet. Notez que, selon ce qui a provoqué l’erreur ICommunicationObject au départ, il peut y avoir d’autres travaux nécessaires pour la récupération.
CommunicationObjectAbortedException ICommunicationObject en cours d'utilisation est dans l'état Aborted (pour plus d'informations, consultez Fonctionnement des modifications d'état). Similaire à CommunicationObjectFaultedException, cette exception indique que l’application a appelé Abort l’objet, éventuellement à partir d’un autre thread, et que l’objet n’est plus utilisable pour cette raison. Le cas échéant, fournit des détails à propos de l'exception interne. Créez un objet. Notez qu'en fonction de ce qui a provoqué l'abandon de ICommunicationObject au départ, il existe peut-être d'autre travail requis à récupérer.
EndpointNotFoundException Le point de terminaison distant cible n’écoute pas. Cela peut résulter d'une partie incorrecte de l'adresse du point de terminaison, irrésolvable, ou du point de terminaison hors service. Par exemple, une erreur DNS, le gestionnaire de files d'attente n’est pas disponible et le service n’est pas en cours d’exécution. L'exception interne fournit des détails, en général à partir du transport sous-jacent. Essayez une autre adresse. Sinon, l’expéditeur peut attendre un certain temps et réessayer en cas de panne du service
ProtocolException Les protocoles de communication, comme décrit par la stratégie du point de terminaison, sont incompatibles entre les points de terminaison. Par exemple, incompatibilité du type de contenu de tramage ou dépassement de la taille maximale des messages. S’il est présent, fournissez plus d’informations sur l’erreur de protocole spécifique. Par exemple, QuotaExceededException est l’exception interne lorsque la cause de l’erreur dépasse MaxReceivedMessageSize. Récupération : vérifiez que l’expéditeur et les paramètres de protocole reçus correspondent. L’une des façons de procéder consiste à réimporter les métadonnées (stratégie) du point de terminaison de service et à utiliser la liaison générée pour recréer le canal.
ServerTooBusyException Le point de terminaison distant écoute, mais n’est pas prêt à traiter les messages. Le cas échéant, l'exception interne fournit des détails sur l'erreur SOAP ou sur l'erreur de niveau transport. Récupération : attendez et réessayez l’opération ultérieurement.
TimeoutException L’opération n’a pas pu se terminer dans le délai d’expiration. Fournit éventuellement des détails à propos du délai d'attente. Attendez et réessayez l’opération ultérieurement.

Définissez un nouveau type d’exception uniquement si ce type correspond à une stratégie de récupération spécifique différente de tous les types d’exceptions existants. Si vous définissez un nouveau type d’exception, il doit dériver de CommunicationException ou de l'une de ses classes dérivées.

Messages d’exception

Les messages d’exception sont ciblés sur l’utilisateur et non sur le programme afin qu’il fournisse suffisamment d’informations pour aider l’utilisateur à comprendre et à résoudre le problème. Les trois parties essentielles d’un bon message d’exception sont les suivantes :

Que s’est-il passé. Fournissez une description claire du problème en utilisant des termes liés à l’expérience de l’utilisateur. Par exemple, un message d’exception incorrect est « Section configuration non valide ». Cela laisse l’utilisateur se demander quelle section de configuration est incorrecte et pourquoi elle est incorrecte. Un message amélioré serait « Section de configuration <customBinding> non valide ». Un message encore meilleur serait « Impossible d’ajouter le transport nommé myTransport à la liaison nommée myBinding, car la liaison a déjà un transport nommé myTransport ». Il s’agit d’un message très spécifique utilisant des termes et des noms que l’utilisateur peut facilement identifier dans le fichier de configuration de l’application. Toutefois, il existe encore quelques composants clés manquants.

Importance de l’erreur. Sauf si le message indique clairement ce que signifie l’erreur, l’utilisateur est susceptible de se demander s’il s’agit d’une erreur irrécupérable ou s’il peut être ignoré. En général, les messages doivent commencer par expliquer la signification ou l’importance de l’erreur. Pour améliorer l’exemple précédent, le message peut être « ServiceHost n’a pas pu s’ouvrir en raison d’une erreur de configuration : Impossible d’ajouter le transport nommé myTransport à la liaison nommée myBinding, car la liaison a déjà un transport nommé myTransport ».

Comment l’utilisateur doit corriger le problème. La partie la plus importante du message aide l’utilisateur à résoudre le problème. Le message doit inclure des conseils ou des indices sur ce qu'il faut vérifier ou corriger pour résoudre le problème. Par exemple, « ServiceHost n’a pas pu s’ouvrir en raison d’une erreur de configuration : Impossible d’ajouter le transport nommé myTransport à la liaison nommée myBinding, car la liaison a déjà un transport nommé myTransport. Vérifiez que la liaison comporte un seul transport ».

Communication d’erreurs

SOAP 1.1 et SOAP 1.2 définissent une structure spécifique pour les erreurs. Il existe des différences entre les deux spécifications mais en général, les types Message et MessageFault sont utilisés pour créer et consommer des erreurs.

Erreur SOAP 1.2 et erreur SOAP 1.1
Erreur SOAP 1.2 (à gauche) et ERREUR SOAP 1.1 (droite). Dans SOAP 1.1, seul l'élément Fault fait l'objet d'une qualification dans l'espace de noms.

SOAP définit un message d’erreur en tant que message qui contient uniquement un élément d’erreur (un élément dont le nom est <env:Fault>) en tant qu’enfant de <env:Body>. Le contenu de l’élément d’erreur diffère légèrement entre SOAP 1.1 et SOAP 1.2, comme illustré dans la figure 1. Toutefois, la System.ServiceModel.Channels.MessageFault classe normalise ces différences en un modèle objet :

public abstract class MessageFault  
{  
    protected MessageFault();  
  
    public virtual string Actor { get; }  
    public virtual string Node { get; }  
    public static string DefaultAction { get; }  
    public abstract FaultCode Code { get; }  
    public abstract bool HasDetail { get; }  
    public abstract FaultReason Reason { get; }  
  
    public T GetDetail<T>();  
    public T GetDetail<T>( XmlObjectSerializer serializer);  
    public System.Xml.XmlDictionaryReader GetReaderAtDetailContents();  
  
    // other methods omitted  
}  

La Code propriété correspond au env:Code (ou faultCode dans SOAP 1.1) et identifie le type de l’erreur. SOAP 1.2 définit cinq valeurs autorisées pour faultCode (par exemple, Sender et Receiver) et définit un Subcode élément qui peut contenir n’importe quelle valeur de sous-code. (Consultez la spécification SOAP 1.2 pour obtenir la liste des codes d’erreur autorisés et leur signification.) SOAP 1.1 a un mécanisme légèrement différent : il définit quatre faultCode valeurs (par exemple, client et serveur) qui peuvent être étendues en définissant entièrement de nouvelles ou en utilisant la notation par points pour créer des valeurs plus spécifiques faultCodes, par exemple Client.Authentication.

Lorsque vous utilisez MessageFault pour programmer des erreurs, le FaultCode.Name et FaultCode.Namespace sont mappés au nom et à l’espace de noms du SOAP 1.2 env:Code ou du SOAP 1.1 faultCode. FaultCode.SubCode se mappe à env:Subcode pour SOAP 1.2 et est nul pour SOAP 1.1.

Vous devez créer de nouveaux sous-codes d’erreur (ou de nouveaux codes d’erreur si vous utilisez SOAP 1.1) s’il est intéressant de distinguer par programmation une erreur. Cela est analogue à la création d’un nouveau type d’exception. Vous devez éviter d’utiliser la notation par points avec des codes d’erreur SOAP 1.1. (Le profil de baseWS-I décourage également l’utilisation de la notation par points de code d’erreur.)

public class FaultCode  
{  
    public FaultCode(string name);  
    public FaultCode(string name, FaultCode subCode);  
    public FaultCode(string name, string ns);  
    public FaultCode(string name, string ns, FaultCode subCode);  
  
    public bool IsPredefinedFault { get; }  
    public bool IsReceiverFault { get; }  
    public bool IsSenderFault { get; }  
    public string Name { get; }  
    public string Namespace { get; }  
    public FaultCode SubCode { get; }  
  
//  methods omitted  
  
}  

La Reason propriété correspond à ( env:Reason ou faultString dans SOAP 1.1) une description lisible par l’homme de la condition d’erreur analogue au message d’une exception. La classe FaultReason (et SOAP env:Reason/faultString) possède la prise en charge intégrée de plusieurs traductions dans l'intérêt de la globalisation.

public class FaultReason  
{  
    public FaultReason(FaultReasonText translation);  
    public FaultReason(IEnumerable<FaultReasonText> translations);  
    public FaultReason(string text);  
  
    public SynchronizedReadOnlyCollection<FaultReasonText> Translations
    {
       get;
    }  
  
 }  

Le contenu des détails d’erreur est exposé sur MessageFault à l’aide de différentes méthodes, notamment le GetDetail<T> et GetReaderAtDetailContents(). Le détail de l’erreur est un élément opaque permettant de transporter des détails supplémentaires sur l’erreur. Cela est utile s’il existe des détails structurés arbitraires que vous souhaitez associer à l’anomalie.

Génération d’erreurs

Cette section explique le processus de génération d’une erreur en réponse à une condition d’erreur détectée dans un canal ou dans une propriété de message créée par le canal. Un exemple classique montre comment renvoyer une erreur en réponse à un message de demande qui contient des données non valides.

Lors de la génération d’une erreur, le canal personnalisé ne doit pas envoyer directement l’erreur, plutôt qu’il doit lever une exception et laisser la couche ci-dessus décider s’il faut convertir cette exception en erreur et comment l’envoyer. Pour faciliter cette conversion, le canal doit fournir une implémentation FaultConverter qui peut convertir l'exception levée par le canal personnalisé en erreur appropriée. FaultConverter est défini comme suit :

public class FaultConverter  
{  
    public static FaultConverter GetDefaultFaultConverter(  
                                   MessageVersion version);  
    protected abstract bool OnTryCreateFaultMessage(  
                                   Exception exception,
                                   out Message message);  
    public bool TryCreateFaultMessage(  
                                   Exception exception,
                                   out Message message);  
}  

Chaque canal qui génère des erreurs personnalisées doit implémenter FaultConverter et le retourner lors d'un appel à GetProperty<FaultConverter>. L'implémentation personnalisée OnTryCreateFaultMessage doit convertir l'exception en défaut ou déléguer au canal interne FaultConverter. Si le canal est un transport, il doit soit convertir l'exception soit déléguer à l'encodeur FaultConverter, ou à l'encodeur par défaut FaultConverter fourni dans WCF. La valeur par défaut FaultConverter convertit les erreurs correspondant aux messages d’erreur spécifiés par WS-Addressing et SOAP. Voici un exemple OnTryCreateFaultMessage d’implémentation.

public override bool OnTryCreateFaultMessage(Exception exception,
                                             out Message message)  
{  
    if (exception is ...)  
    {  
        message = ...;  
        return true;  
    }  
  
#if IMPLEMENTING_TRANSPORT_CHANNEL  
    FaultConverter encoderConverter =
                    this.encoder.GetProperty<FaultConverter>();  
    if ((encoderConverter != null) &&
        (encoderConverter.TryCreateFaultMessage(  
         exception, out message)))  
    {  
        return true;  
    }  
  
    FaultConverter defaultConverter =
                   FaultConverter.GetDefaultFaultConverter(  
                   this.channel.messageVersion);  
    return defaultConverter.TryCreateFaultMessage(  
                   exception,
                   out message);  
#else  
    FaultConverter inner =
                   this.innerChannel.GetProperty<FaultConverter>();  
    if (inner != null)  
    {  
        return inner.TryCreateFaultMessage(exception, out message);  
    }  
    else  
    {  
        message = null;  
        return false;  
    }  
#endif  
}  

Une conséquence de ce modèle est que les exceptions levées entre des couches pour les conditions d'erreur qui requièrent des erreurs doivent contenir suffisamment d'informations pour que le générateur d'erreurs correspondant crée l'erreur correcte. En tant qu’auteur de canal personnalisé, vous pouvez définir des types d’exceptions qui correspondent à différentes conditions d’erreur si ces exceptions n’existent pas déjà. Notez que les exceptions qui traversent les couches de canal doivent communiquer la condition d’erreur plutôt que les données d’erreur opaques.

Catégories d’erreurs

Il existe généralement trois catégories d’erreurs :

  1. Erreurs envahissant toute la pile. Ces erreurs peuvent être rencontrées à n’importe quelle couche de la pile de canaux, par exemple InvalidCardinalityAddressingException.

  2. Erreurs qui peuvent être rencontrées n’importe où au-dessus d’une certaine couche de la pile, par exemple certaines erreurs relatives à une transaction transmise ou à des rôles de sécurité.

  3. Erreurs dirigées vers une couche unique dans la pile, par exemple, erreurs comme les erreurs de numéro de séquence WS-RM.

Catégorie 1. Les défaillances sont généralement de type WS-Addressing et de type SOAP. La classe de base FaultConverter fournie par WCF convertit les erreurs correspondant aux messages d’erreur spécifiés par WS-Addressing et SOAP afin que vous n’ayez pas à gérer la conversion de ces exceptions vous-même.

Catégorie 2. Les erreurs se produisent lorsqu’une couche ajoute une propriété au message qui ne consomme pas complètement les informations de message relatives à cette couche. Des erreurs peuvent être détectées ultérieurement lorsqu’une couche supérieure demande à la propriété de message de traiter les informations de message plus loin. Ces canaux doivent implémenter l’élément GetProperty spécifié précédemment pour permettre à la couche supérieure de renvoyer l’erreur correcte. Un exemple de cela est la transactionMessageProperty. Cette propriété est ajoutée au message sans valider entièrement toutes les données de l’en-tête (cela peut impliquer le contact du coordinateur de transaction distribué (DTC).

Catégorie 3. Les erreurs sont générées et envoyées par une seule couche dans le processeur. Par conséquent, toutes les exceptions sont contenues dans la couche. Pour améliorer la cohérence entre les canaux et faciliter la maintenance, votre canal personnalisé doit utiliser le modèle spécifié précédemment pour générer des messages d’erreur même pour les erreurs internes.

Interprétation des erreurs reçues

Cette section fournit des conseils pour générer l’exception appropriée lors de la réception d’un message d’erreur. L’arbre de décision pour le traitement d’un message à chaque couche de la pile est le suivant :

  1. Si la couche considère que le message n’est pas valide, la couche doit effectuer son traitement « message non valide ». Ce traitement est spécifique à la couche, mais peut inclure la suppression du message, le traçage, ou la levée d’une exception qui est convertie en erreur. Par exemple, la sécurité reçoit un message qui n’est pas sécurisé correctement ou RM recevant un message avec un numéro de séquence incorrect.

  2. Sinon, si le message est un message d’erreur qui s’applique spécifiquement à la couche et que le message n’est pas significatif en dehors de l’interaction de la couche, la couche doit gérer la condition d’erreur. Exemple : une erreur de séquence RM refusée non significative pour les couches au-dessus du canal RM et qui implique de provoquer une erreur dans le canal RM et de lever à partir d'opérations en attente.

  3. Sinon, le message doit être retourné par Request() ou Receive(). Cela inclut les cas où la couche reconnaît l'erreur, mais l'erreur indique juste qu'une demande a échoué et n'implique pas de provoquer une erreur dans le canal et de lever à partir d'opérations en attente. Pour améliorer la facilité d’utilisation dans ce cas, la couche doit implémenter GetProperty<FaultConverter> et retourner une FaultConverter classe dérivée qui peut convertir l’erreur en exception en substituant OnTryCreateException.

Le modèle objet suivant prend en charge la conversion de messages en exceptions :

public class FaultConverter  
{  
    public static FaultConverter GetDefaultFaultConverter(  
                                  MessageVersion version);  
    protected abstract bool OnTryCreateException(  
                                 Message message,
                                 MessageFault fault,
                                 out Exception exception);  
    public bool TryCreateException(  
                                 Message message,
                                 MessageFault fault,
                                 out Exception exception);  
}  

Une couche de canal peut implémenter GetProperty<FaultConverter> afin de convertir des messages d’erreur en exceptions. Pour ce faire, remplacez OnTryCreateException et inspectez le message d’erreur. Si cela est reconnu, effectuez la conversion, sinon demandez au canal interne de l'effectuer. Les canaux de transport doivent déléguer à FaultConverter.GetDefaultFaultConverter pour obtenir le FaultConverter SOAP/WS-Addressing par défaut.

Une implémentation classique ressemble à ceci :

public override bool OnTryCreateException(  
                            Message message,
                            MessageFault fault,
                            out Exception exception)  
{  
    if (message.Action == "...")  
    {  
        exception = ...;  
        return true;  
    }  
    // OR  
    if ((fault.Code.Name == "...") && (fault.Code.Namespace == "..."))  
    {  
        exception = ...;  
        return true;  
    }  
  
    if (fault.IsMustUnderstand)  
    {  
        if (fault.WasHeaderNotUnderstood(  
                   message.Headers, "...", "..."))  
        {  
            exception = new ProtocolException(...);  
            return true;  
        }  
    }  
  
#if IMPLEMENTING_TRANSPORT_CHANNEL  
    FaultConverter encoderConverter =
              this.encoder.GetProperty<FaultConverter>();  
    if ((encoderConverter != null) &&
        (encoderConverter.TryCreateException(  
                              message, fault, out exception)))  
    {  
        return true;  
    }  
  
    FaultConverter defaultConverter =  
             FaultConverter.GetDefaultFaultConverter(  
                             this.channel.messageVersion);  
    return defaultConverter.TryCreateException(  
                             message, fault, out exception);  
#else  
    FaultConverter inner =
                    this.innerChannel.GetProperty<FaultConverter>();  
    if (inner != null)  
    {  
        return inner.TryCreateException(message, fault, out exception);  
    }  
    else  
    {  
        exception = null;  
        return false;  
    }  
#endif  
}  

Pour des conditions d’erreur spécifiques qui ont des scénarios de récupération distincts, envisagez de définir une classe dérivée de ProtocolException.

Traitement de MustUnderstand

SOAP définit une erreur générale pour signaler qu’un en-tête requis n’a pas été compris par le récepteur. Cette erreur est appelée mustUnderstand erreur. Dans WCF, les canaux personnalisés ne génèrent mustUnderstand jamais d’erreurs. En revanche, le Répartiteur WCF, situé en haut de la pile de communication WCF, vérifie que tous les en-têtes marqués comme MustUndestand=true ont été compris par la pile sous-jacente. Si quelque chose n'a pas été compris, une mustUnderstand faute est générée à ce stade. (L’utilisateur peut choisir de désactiver ce mustUnderstand traitement et que l’application reçoit tous les en-têtes de message. Dans ce cas, l’application est responsable de l’exécution mustUnderstand du traitement.) L’erreur générée inclut un en-tête NotUnderstood qui contient les noms de tous les en-têtes avec MustUnderstand=true qui n’ont pas été compris.

Si votre canal de protocole envoie un en-tête personnalisé avec MustUnderstand=true et reçoit une mustUnderstand erreur, il doit déterminer si cette erreur est due à l’en-tête envoyé. Il existe deux membres sur la MessageFault classe qui sont utiles pour cela :

public class MessageFault  
{  
    ...  
    public bool IsMustUnderstandFault { get; }  
    public static bool WasHeaderNotUnderstood(MessageHeaders headers,
        string name, string ns) { }  
    ...  
  
}  

IsMustUnderstandFault retourne true si l’erreur est une mustUnderstand erreur. WasHeaderNotUnderstood retourne la valeur true si l'en-tête avec le nom et l'espace de noms spécifiés est inclus dans l'erreur en tant qu'en-tête NotUnderstood. Sinon, falseest retourné.

Si un canal émet un en-tête marqué MustUnderstand = true, cette couche doit également implémenter le modèle d’API Génération d’exceptions et convertir mustUnderstand les erreurs provoquées par cet en-tête en une exception plus utile, comme décrit précédemment.

Traçage

Le .NET Framework fournit un mécanisme permettant de suivre l’exécution du programme comme moyen de diagnostiquer les applications de production ou les problèmes intermittents, où il n’est pas possible simplement d’attacher un débogueur et d’effectuer un pas à pas dans le code. Les principaux composants de ce mécanisme se trouvent dans l’espace System.Diagnostics de noms et se composent des éléments suivants :

  • System.Diagnostics.TraceSource, qui est la source des informations de trace à écrire, System.Diagnostics.TraceListener, qui est une classe de base abstraite pour les écouteurs concrets qui reçoivent les informations à tracer depuis le TraceSource et les diffusent vers une destination spécifique à chaque écouteur. Par exemple, XmlWriterTraceListener génère des informations de trace dans un fichier XML. Enfin, System.Diagnostics.TraceSwitch, qui permet à l'utilisateur de l'application de contrôler les commentaires de suivi et qui est en général spécifié dans la configuration.

  • Outre les composants principaux, vous pouvez utiliser l’outil Visionneuse de traces de service (SvcTraceViewer.exe) pour afficher et rechercher des traces WCF. L'outil est conçu spécifiquement pour les fichiers de trace générés par WCF et écrits à l'aide de XmlWriterTraceListener. La figure suivante montre les différents composants impliqués dans le suivi.

Composants de suivi

Suivi à partir d'un canal personnalisé

Les canaux personnalisés doivent écrire des messages de suivi pour faciliter le diagnostic des problèmes lorsqu’il n’est pas possible d’attacher un débogueur à l’application en cours d’exécution. Cela implique deux tâches de haut niveau : instancier un TraceSource et appeler ses méthodes pour écrire des traces.

Lors de l’instanciation d’un TraceSource, la chaîne que vous spécifiez devient le nom de cette source. Ce nom est utilisé pour configurer (activer/désactiver/définir le niveau de suivi) la source de trace. Il apparaît également dans la sortie de suivi elle-même. Les canaux personnalisés doivent utiliser un nom de source unique pour aider les lecteurs de la sortie de trace à comprendre où proviennent les informations de trace. L'usage consiste à utiliser le nom de l'assembly qui écrit les informations en tant que nom de la source de suivi. Par exemple, WCF utilise System.ServiceModel comme source de trace pour les informations écrites à partir de l’assembly System.ServiceModel.

Une fois que vous avez une source de trace, vous appelez ses méthodes TraceData, TraceEvent, ou TraceInformation pour écrire des entrées de trace dans les écouteurs de trace. Pour chaque entrée de trace que vous écrivez, vous devez classifier le type d’événement comme l’un des types d’événements définis dans TraceEventType. Cette classification et le paramètre de niveau de trace dans la configuration déterminent si l’entrée de trace est transmise à l’écouteur. Par exemple, affecter au niveau de suivi dans la configuration la valeur Warning permet d'écrire les entrées de suivi Warning, Error et Critical mais de bloquer les entrées Informations et En clair. Voici un exemple d'instanciation d'une source de suivi et d'écriture d'une entrée au niveau Informations :

using System.Diagnostics;  
//...  
TraceSource udpSource = new TraceSource("Microsoft.Samples.Udp");  
//...  
udpsource.TraceInformation("UdpInputChannel received a message");  

Importante

Il est vivement recommandé de spécifier un nom de source de trace unique à votre canal personnalisé pour aider les lecteurs de sortie de trace à comprendre l’origine de la sortie.

Intégration au Trace Viewer

Les traces générées par votre canal peuvent être sorties dans un format lisible par l’outil Visionneuse de trace de service (SvcTraceViewer.exe) en utilisant System.Diagnostics.XmlWriterTraceListener comme écouteur de trace. Ce n’est pas quelque chose que vous, en tant que développeur de canaux, devez faire. Il s’agit plutôt de l’utilisateur de l’application (ou de la personne qui résolve les problèmes de l’application) qui doit configurer cet écouteur de suivi dans le fichier de configuration de l’application. Par exemple, la configuration suivante génère des informations de trace à partir des deux System.ServiceModel et Microsoft.Samples.Udp vers le fichier nommé TraceEventsFile.e2e:

<configuration>  
  <system.diagnostics>  
    <sources>  
      <!-- configure System.ServiceModel trace source -->  
      <source name="System.ServiceModel" switchValue="Verbose"
              propagateActivity="true">  
        <listeners>  
          <add name="e2e" />  
        </listeners>  
      </source>  
      <!-- configure Microsoft.Samples.Udp trace source -->  
      <source name="Microsoft.Samples.Udp" switchValue="Verbose" >  
        <listeners>  
          <add name="e2e" />  
        </listeners>  
      </source>  
    </sources>  
    <!--   
    Define a shared trace listener that outputs to TraceFile.e2e  
    The listener name is e2e   
    -->  
    <sharedListeners>  
      <add name="e2e" type="System.Diagnostics.XmlWriterTraceListener"  
        initializeData=".\TraceFile.e2e"/>  
    </sharedListeners>  
    <trace autoflush="true" />  
  </system.diagnostics>  
</configuration>  

Suivi des données structurées

System.Diagnostics.TraceSource a une TraceData méthode qui accepte un ou plusieurs objets à inclure dans l’entrée de trace. En général, la Object.ToString méthode est appelée sur chaque objet et la chaîne résultante est écrite dans le cadre de l’entrée de trace. Lorsque vous utilisez System.Diagnostics.XmlWriterTraceListener pour générer des traces, vous pouvez passer un System.Xml.XPath.IXPathNavigable objet de données à TraceData. L’entrée de trace résultante inclut le code XML fourni par le System.Xml.XPath.XPathNavigator. Voici un exemple d’entrée avec des données d’application XML :

<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent">  
  <System xmlns="...">  
    <EventID>12</EventID>  
    <Type>3</Type>  
    <SubType Name="Information">0</SubType>  
    <Level>8</Level>  
    <TimeCreated SystemTime="2006-01-13T22:58:03.0654832Z" />  
    <Source Name="Microsoft.ServiceModel.Samples.Udp" />  
    <Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" />  
    <Execution  ProcessName="UdpTestConsole"
                ProcessID="3348" ThreadID="4" />  
    <Channel />  
    <Computer>COMPUTER-LT01</Computer>  
  </System>  
<!-- XML application data -->  
  <ApplicationData>  
  <TraceData>  
   <DataItem>  
   <TraceRecord
     Severity="Information"  
     xmlns="…">  
        <TraceIdentifier>some trace id</TraceIdentifier>  
        <Description>EndReceive called</Description>  
        <AppDomain>UdpTestConsole.exe</AppDomain>  
        <Source>UdpInputChannel</Source>  
      </TraceRecord>  
    </DataItem>  
  </TraceData>  
  </ApplicationData>  
</E2ETraceEvent>  

La visionneuse de trace WCF comprend le schéma de l’élément TraceRecord affiché précédemment et extrait les données de ses éléments enfants et les affiche dans un format tabulaire. Votre canal doit utiliser ce schéma lors du suivi de données d'application structurées pour aider les utilisateurs de Svctraceviewer.exe à lire les données.