Condividi tramite


Gestione di eccezioni e errori

Le eccezioni vengono usate per comunicare gli errori in locale all'interno del servizio o all'implementazione del client. Gli errori, d'altra parte, vengono usati per comunicare errori attraverso i limiti del servizio, ad esempio dal server al client o viceversa. Oltre agli errori, i canali di trasporto usano spesso meccanismi specifici del trasporto per comunicare gli errori a livello di trasporto. Ad esempio, il trasporto HTTP utilizza codici di stato come 404 per comunicare un URL dell'endpoint inesistente (non c'è alcun endpoint per segnalare un errore). Questo documento è costituito da tre sezioni che forniscono indicazioni agli autori di canali personalizzati. La prima sezione fornisce indicazioni su quando e su come definire e generare eccezioni. La seconda sezione fornisce indicazioni per la generazione e la gestione di anomalie. La terza sezione illustra come fornire informazioni di traccia per facilitare l'utente del canale personalizzato nella risoluzione dei problemi relativi alle applicazioni in esecuzione.

Eccezioni

Quando si genera un'eccezione, è necessario tenere presente due aspetti: per prima cosa deve essere di un tipo che consente agli utenti di scrivere codice corretto in grado di reagire in modo appropriato all'eccezione. In secondo luogo, deve fornire informazioni sufficienti per l'utente per comprendere cosa è andato storto, l'impatto sugli errori e come risolverlo. Nelle sezioni seguenti vengono fornite indicazioni sui tipi di eccezione e i messaggi per i canali windows Communication Foundation (WCF). Sono inoltre disponibili indicazioni generali sulle eccezioni in .NET nel documento Linee guida per la progettazione per le eccezioni.

Tipi di eccezione

Tutte le eccezioni generate dai canali devono essere un System.TimeoutException, un System.ServiceModel.CommunicationException o un tipo derivato da CommunicationException. Le eccezioni, ad esempio ObjectDisposedException , possono anche essere generate, ma solo per indicare che il codice chiamante ha usato in modo improprio il canale. Se un canale viene usato correttamente, deve generare solo le eccezioni indicate. WCF fornisce sette tipi di eccezione che derivano da CommunicationException e sono progettati per essere usati dai canali. Esistono altre eccezioni derivate da CommunicationException che sono progettate per essere usate da altre parti del sistema. Questi tipi di eccezione sono:

Tipo di eccezione Significato Contenuto dell'eccezione interna Strategia di recupero
AddressAlreadyInUseException L'indirizzo dell'endpoint specificato per l'ascolto è già in uso. Se presente, fornisce altri dettagli sull'errore di trasporto che ha causato questa eccezione. Per esempio. PipeException, HttpListenerException o SocketException. Provare un indirizzo diverso.
AddressAccessDeniedException Il processo non è autorizzato ad accedere all'indirizzo dell'endpoint specificato per l'ascolto. Se presente, fornisce altri dettagli sull'errore di trasporto che ha causato questa eccezione. Ad esempio, PipeException o HttpListenerException. Provare con credenziali diverse.
CommunicationObjectFaultedException L'oggetto ICommunicationObject usato si trova nello stato Faulted (per altre informazioni, vedere Informazioni sulle modifiche dello stato). Si noti che quando un oggetto con più chiamate in sospeso passa allo stato Faulted, una sola chiamata genera un'eccezione correlata all'errore e il resto delle chiamate genera un'eccezione CommunicationObjectFaultedException. Questa eccezione viene generata in genere perché un'applicazione ignora alcune eccezioni e tenta di usare un oggetto già difettoso, possibilmente in un thread diverso da quello che ha rilevato l'eccezione originale. Se presente, fornisce informazioni dettagliate sull'eccezione interna. Creare un nuovo oggetto. Si noti che a seconda di ciò che ha causato l'errore ICommunicationObject in primo luogo, potrebbe esserci un altro lavoro necessario per il ripristino.
CommunicationObjectAbortedException L'oggetto ICommunicationObject utilizzato è stato annullato. Per ulteriori informazioni, vedere Comprendere i cambiamenti di stato. Analogamente a CommunicationObjectFaultedException, questa eccezione indica che l'applicazione ha chiamato Abort sull'oggetto, possibilmente da un altro thread, e l'oggetto non è più utilizzabile per tale motivo. Se presente, fornisce informazioni dettagliate sull'eccezione interna. Creare un nuovo oggetto. Si noti che, a seconda di ciò che ha causato l'interruzione di ICommunicationObject in primo luogo, potrebbero esserci altri lavori necessari per il ripristino.
EndpointNotFoundException L'endpoint remoto di destinazione non è in ascolto. Ciò può derivare da qualsiasi parte dell'indirizzo dell'endpoint che sia non corretta, irrisolvibile o dall'endpoint che è inattivo. Gli esempi includono l'errore DNS, Queue Manager non disponibile e il servizio non è in esecuzione. L'eccezione interna fornisce dettagli, in genere dal trasporto sottostante. Provare un indirizzo diverso. In alternativa, il mittente potrebbe attendere un po ' e riprovare nel caso in cui il servizio fosse inattivo
ProtocolException I protocolli di comunicazione, come descritto dai criteri dell'endpoint, non corrispondono tra gli endpoint. Ad esempio, il tipo di contenuto di frame non corrisponde o la dimensione massima del messaggio è stata superata. Se presente, vengono fornite altre informazioni sull'errore di protocollo specifico. Ad esempio, QuotaExceededException è l'eccezione interna quando la causa dell'errore supera MaxReceivedMessageSize. Ripristino: verificare che le impostazioni del protocollo mittente e ricevuto corrispondano. Un modo per eseguire questa operazione consiste nel riimportare i metadati (criteri) dell'endpoint di servizio e usare l'associazione generata per ricreare il canale.
ServerTooBusyException L'endpoint remoto è in ascolto ma non è pronto per elaborare i messaggi. Se presente, l'eccezione interna fornisce i dettagli dell'errore SOAP o del livello di trasporto. Ripristino: attendere e ripetere l'operazione in un secondo momento.
TimeoutException Impossibile completare l'operazione entro il periodo di timeout. Può fornire informazioni dettagliate sul timeout. Attendere e ripetere l'operazione in un secondo momento.

Definire un nuovo tipo di eccezione solo se tale tipo corrisponde a una strategia di ripristino specifica diversa da tutti i tipi di eccezione esistenti. Se si definisce un nuovo tipo di eccezione, deve derivare da o da CommunicationException una delle relative classi derivate.

Messaggi di eccezione

I messaggi di eccezione sono destinati all'utente non al programma, pertanto devono fornire informazioni sufficienti per aiutare l'utente a comprendere e risolvere il problema. Le tre parti essenziali di un messaggio di eccezione valido sono:

Cos'è successo. Fornire una descrizione chiara del problema usando termini correlati all'esperienza dell'utente. Ad esempio, un messaggio di eccezione non valido sarà "Sezione di configurazione non valida". In questo modo l'utente chiede quale sezione di configurazione non è corretta e perché non è corretta. Un messaggio migliorato è "Sezione <di configurazione non valida customBinding>". Un messaggio ancora migliore sarebbe "Impossibile aggiungere il trasporto denominato myTransport all'associazione denominata myBinding perché l'associazione ha già un trasporto denominato myTransport". Si tratta di un messaggio molto specifico che usa termini e nomi che l'utente può facilmente identificare nel file di configurazione dell'applicazione. Tuttavia, ci sono ancora alcuni componenti chiave mancanti.

Significato dell'errore. A meno che il messaggio non indichi chiaramente il significato dell'errore, è probabile che l'utente si chiesta se si tratta di un errore irreversibile o se può essere ignorato. In generale, i messaggi dovrebbero iniziare con il significato o l'importanza dell'errore. Per migliorare il precedente esempio, il messaggio potrebbe essere "ServiceHost non è riuscito ad aprirsi a causa di un errore di configurazione: Impossibile aggiungere il trasporto denominato myTransport al binding denominato myBinding perché il binding ha già un trasporto denominato myTransport".

Come l'utente deve risolvere il problema. La parte più importante del messaggio è aiutare l'utente a risolvere il problema. Il messaggio deve includere alcune indicazioni o suggerimenti su cosa controllare o correggere per risolvere il problema. Ad esempio, "impossibile aprire ServiceHost a causa di un errore di configurazione: non è possibile aggiungere il trasporto denominato myTransport al binding denominato myBinding perché il binding ha già un trasporto denominato myTransport. Assicurarsi che nell'associazione sia presente un solo trasporto".

Comunicazione di errori

SOAP 1.1 e SOAP 1.2 definiscono entrambe una struttura specifica per gli errori. Esistono alcune differenze tra le due specifiche, ma in generale, i tipi "Message" e "MessageFault" vengono usati per creare e consumare guasti.

Errore SOAP 1.2 e errore SOAP 1.1
Errore SOAP 1.2 (a sinistra) e errore SOAP 1.1 (a destra). In SOAP 1.1 solo l'elemento Fault è qualificato dallo spazio dei nomi.

SOAP definisce un messaggio di errore come messaggio che contiene solo un elemento di errore (un elemento il cui nome è <env:Fault>) come figlio di <env:Body>. Il contenuto dell'elemento di errore differisce leggermente tra SOAP 1.1 e SOAP 1.2, come illustrato nella figura 1. Tuttavia, la System.ServiceModel.Channels.MessageFault classe normalizza queste differenze in un modello a oggetti:

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 proprietà corrisponde a env:Code (o faultCode in SOAP 1.1) e identifica il tipo dell'errore. SOAP 1.2 definisce cinque valori consentiti per faultCode (ad esempio Sender e Receiver) e definisce un Subcode elemento che può contenere qualsiasi valore di codice secondario. Per l'elenco dei codici di errore consentiti e il relativo significato, vedere la specifica SOAP 1.2 . SOAP 1.1 ha un meccanismo leggermente diverso: definisce quattro faultCode valori (ad esempio, Client e Server) che possono essere estesi definendo quelli completamente nuovi o usando la notazione punto per creare faultCodes, ad esempio Client.Authentication.

Quando si usa MessageFault per gestire gli errori, FaultCode.Name e FaultCode.Namespace mappano al nome e allo spazio dei nomi di SOAP 1.2 env:Code o SOAP 1.1 faultCode. FaultCode.SubCode esegue il mapping a env:Subcode per SOAP 1.2 ed è Null per SOAP 1.1.

È consigliabile creare nuovi codici secondari di errore (o nuovi codici di errore se si usa SOAP 1.1) se è interessante distinguere a livello di codice un errore. Questo è analogo alla creazione di un nuovo tipo di eccezione. È consigliabile evitare di usare la notazione con punti con i codici di errore SOAP 1.1. Il Basic ProfileWS-I sconsiglia anche l'uso della notazione punto del codice di errore.

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 proprietà corrisponde a env:Reason (o faultString in SOAP 1.1) una descrizione leggibile della condizione di errore analoga al messaggio di un'eccezione. La FaultReason classe (e SOAP env:Reason/faultString) include il supporto predefinito per avere più traduzioni nell'interesse della globalizzazione.

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

Il contenuto dei dettagli di errore viene esposto in MessageFault usando vari metodi, tra cui GetDetail<T> e GetReaderAtDetailContents(). Il dettaglio dell'errore è un elemento opaco per trasportare dettagli aggiuntivi sull'errore. Ciò è utile se c'è qualche dettaglio strutturato arbitrario che si vuole associare al guasto.

Generazione di guasti

Questa sezione illustra il processo di generazione di un errore in risposta a una condizione di errore rilevata in un canale o in una proprietà messaggio creata dal canale. Un esempio tipico è l'invio di un errore in risposta a un messaggio di richiesta contenente dati non validi.

Quando si genera un errore, il canale personalizzato non deve inviare direttamente l'errore, ma deve generare un'eccezione e lasciare che il livello precedente decida se convertire l'eccezione in un errore e come inviarla. Per facilitare questa conversione, il canale deve fornire un'implementazione FaultConverter in grado di convertire l'eccezione generata dal canale personalizzato nell'errore appropriato. FaultConverter è definito come:

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);  
}  

Ogni canale che genera errori personalizzati deve implementare FaultConverter e restituirlo da una chiamata a GetProperty<FaultConverter>. L'implementazione personalizzata OnTryCreateFaultMessage deve convertire l'eccezione in un errore o delegare al canale interno FaultConverter. Se il canale è un trasporto, deve o convertire l'eccezione, o delegare al codificatore FaultConverter o all'impostazione predefinita FaultConverter fornita in WCF. L'impostazione predefinita FaultConverter converte gli errori corrispondenti ai messaggi di errore specificati da WS-Addressing e SOAP. Di seguito è riportato un esempio OnTryCreateFaultMessage di implementazione.

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  
}  

Un'implicazione di questo modello è che le eccezioni generate tra livelli per condizioni di errore che richiedono guasti devono contenere informazioni sufficienti affinché il generatore di guasti corrispondente possa creare il guasto corretto. In qualità di autore di canali personalizzati, è possibile definire tipi di eccezione che corrispondono a condizioni di errore diverse se tali eccezioni non esistono già. Si noti che le eccezioni che attraversano i livelli del canale devono comunicare la condizione di errore anziché i dati di errore opachi.

Categorie di errore

Esistono in genere tre categorie di errori:

  1. Errori che sono diffusi in tutto lo stack. Questi errori possono essere rilevati a qualsiasi livello nello stack di canali, ad esempio InvalidCardinalityAddressingException.

  2. Errori che possono essere rilevati ovunque sopra un determinato livello nello stack, ad esempio alcuni errori relativi a una transazione propagata o ai ruoli di sicurezza.

  3. Errori che riguardano un singolo livello nello stack, ad esempio errori di sequenza WS-RM.

Categoria 1. Gli errori sono in genere WS-Addressing e SOAP. La classe base FaultConverter fornita da WCF converte gli errori corrispondenti ai messaggi di errore specificati da WS-Addressing e SOAP, pertanto non è necessario gestire manualmente la conversione di queste eccezioni.

Categoria 2. Gli errori si verificano quando un livello aggiunge una proprietà al messaggio che non utilizza completamente le informazioni sul messaggio relative a tale livello. Gli errori possono essere rilevati in un secondo momento quando un livello superiore chiede alla proprietà del messaggio di elaborare ulteriormente le informazioni del messaggio. Tali canali devono implementare l'oggetto GetProperty specificato in precedenza per consentire al livello superiore di restituire l'errore corretto. Un esempio è TransactionMessageProperty. Questa proprietà viene aggiunta al messaggio senza convalidare completamente tutti i dati nell'intestazione. In questo modo, potrebbe essere necessario contattare il coordinatore delle transazioni distribuite (DTC).

Categoria 3. Gli errori vengono generati e inviati solo da un singolo livello nel processore. Pertanto tutte le eccezioni sono contenute all'interno del livello. Per migliorare la coerenza tra i canali e semplificare la manutenzione, il canale personalizzato deve usare il modello specificato in precedenza per generare messaggi di errore anche per gli errori interni.

Interpretazione degli errori ricevuti

In questa sezione vengono fornite indicazioni per la generazione dell'eccezione appropriata quando si riceve un messaggio di errore. L'albero delle decisioni per l'elaborazione di un messaggio a ogni livello nello stack è il seguente:

  1. Se il livello considera il messaggio non valido, il livello deve eseguire l'elaborazione del messaggio non valido. Tale elaborazione è specifica del livello, ma può includere l'eliminazione del messaggio, il tracciamento o la generazione di un'eccezione che viene convertita in un guasto. Alcuni esempi includono il caso in cui la sicurezza riceve un messaggio non protetto correttamente o l'RM riceve un messaggio con un numero di sequenza non valido.

  2. In caso contrario, se il messaggio è un messaggio di errore che si applica in modo specifico al livello e il messaggio non è significativo all'esterno dell'interazione del livello, il livello deve gestire la condizione di errore. Un esempio di questo è un guasto RM Sequence Refused, che è privo di significato per i livelli superiori al canale RM e che implica il guasto del canale RM e l'interruzione delle operazioni in sospeso.

  3. In caso contrario, il messaggio deve essere restituito da Request() o Receive(). Sono inclusi i casi in cui il livello riconosce l'errore, ma l'errore indica semplicemente che una richiesta non è riuscita e non implica un errore del canale o un'interruzione delle operazioni in sospeso. Per migliorare l'usabilità in questo caso, il livello deve implementare GetProperty<FaultConverter> e restituire una FaultConverter classe derivata in grado di convertire l'errore in un'eccezione eseguendo l'override di OnTryCreateException.

Il modello a oggetti seguente supporta la conversione dei messaggi in eccezioni:

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);  
}  

Un livello di canale può implementare GetProperty<FaultConverter> per supportare la conversione dei messaggi di errore in eccezioni. A tale scopo, eseguire l'override OnTryCreateException e controllare il messaggio di errore. Se riconosciuto, eseguire la conversione; altrimenti, chiedere al canale interno di effettuarla. I canali di trasporto devono delegare a FaultConverter.GetDefaultFaultConverter per ottenere il convertitore di errore predefinito SOAP/WS-Addressing.

Un'implementazione tipica è simile alla seguente:

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  
}  

Per condizioni di errore specifiche con scenari di ripristino distinti, è consigliabile definire una classe derivata di ProtocolException.

Elaborazione MustUnderstand

SOAP definisce un errore generale per segnalare che un'intestazione obbligatoria non è stata compresa dal ricevitore. Questo errore è noto come mustUnderstand errore. In WCF i canali personalizzati non generano mai mustUnderstand errori. Al contrario, il Dispatcher WCF, che si trova nella parte superiore dello stack di comunicazione WCF, verifica che tutte le intestazioni contrassegnate come MustUnderstand=true siano state comprese dallo stack sottostante. Se qualcuno non è stato compreso, a quel punto viene generato un mustUnderstand errore. L'utente può scegliere di disattivare questa mustUnderstand elaborazione e chiedere all'applicazione di ricevere tutte le intestazioni del messaggio. In tal caso l'applicazione è responsabile dell'elaborazione mustUnderstand . L'errore generato include un'intestazione NotUnderstood che contiene i nomi di tutte le intestazioni con MustUnderstand=true che non sono state comprese.

Se il canale del protocollo invia un'intestazione personalizzata con MustUnderstand=true e riceve un mustUnderstand errore, deve determinare se l'errore è dovuto all'intestazione inviata. Esistono due membri della MessageFault classe utili per questo:

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

IsMustUnderstandFault restituisce true se l'errore è un mustUnderstand errore. WasHeaderNotUnderstood restituisce true se l'intestazione con il nome e il namespace specificati è inclusa nell'errore come intestazione NotUnderstood. In caso contrario, restituisce false.

Se un canale genera un'intestazione contrassegnata come MustUnderstand = true, tale livello deve implementare anche il modello api di generazione eccezioni e deve convertire mustUnderstand gli errori causati da tale intestazione in un'eccezione più utile, come descritto in precedenza.

Tracciamento

.NET Framework fornisce un meccanismo per tracciare l'esecuzione del programma come modo per diagnosticare le applicazioni di produzione o problemi intermittenti in cui non è possibile collegare semplicemente un debugger ed eseguire il codice. I componenti principali di questo meccanismo si trovano nello spazio dei nomi System.Diagnostics e sono costituiti da:

Componenti di tracciamento

Tracciamento da un canale personalizzato

I canali personalizzati devono scrivere messaggi di traccia per facilitare la diagnosi dei problemi quando non è possibile collegare un debugger all'applicazione in esecuzione. Ciò comporta due attività di alto livello: creazione di un'istanza di TraceSource e chiamare i suoi metodi per scrivere tracce.

Quando si crea un'istanza di TraceSource, la stringa specificata diventa il nome dell'origine. Questo nome viene usato per configurare la sorgente di traccia (abilitare/disabilitare/impostare il livello di tracciamento). Viene visualizzato anche nell'output di traccia stesso. I canali personalizzati devono usare un nome di origine univoco per consentire ai lettori dell'output di traccia di comprendere da dove provengono le informazioni di traccia. L'utilizzo del nome dell'assembly che scrive le informazioni come nome dell'origine della traccia è procedura comune. Ad esempio, WCF usa System.ServiceModel come origine di traccia per informazioni scritte dall'assembly System.ServiceModel.

Dopo aver creato un'origine di traccia, chiamare i metodi TraceData, TraceEvent o TraceInformation per scrivere voci di traccia nei listener di traccia. Per ogni voce di traccia scritta, è necessario classificare il tipo di evento come uno dei tipi di evento definiti in TraceEventType. Questa classificazione e l'impostazione del livello di traccia nella configurazione determinano se la voce di traccia viene inviata all'ascoltatore. Ad esempio, impostando il livello di traccia nella configurazione su Warning, Warning, Error e Critical le voci di traccia possono essere scritte, ma impedisce le voci informazioni e Verbose. Ecco un esempio di creazione di un'istanza di una fonte di traccia e della scrittura di una voce al livello Informazioni:

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

Importante

È consigliabile specificare un nome di origine di traccia univoco per il canale personalizzato per consentire ai lettori di output di traccia di comprendere da dove proviene l'output.

Integrazione con il visualizzatore di traccia

Le tracce generate dal tuo canale possono essere prodotte in un formato leggibile dallo strumento Visualizzatore tracce del servizio (SvcTraceViewer.exe) usando System.Diagnostics.XmlWriterTraceListener come strumento di ascolto. Questo non è qualcosa che lo sviluppatore di canali deve fare. È invece l'utente dell'applicazione (o la persona che risolve i problemi dell'applicazione) a dover configurare questo ascoltatore di traccia nel file di configurazione dell'applicazione. Ad esempio, la configurazione seguente restituisce informazioni di traccia da System.ServiceModel e Microsoft.Samples.Udp al file denominato 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>  

Traccia di dati strutturati

System.Diagnostics.TraceSource dispone di un TraceData metodo che accetta uno o più oggetti da includere nella voce di traccia. In generale, il metodo Object.ToString viene chiamato su ogni oggetto e la stringa risultante viene scritta come parte della voce di traccia. Quando si usano System.Diagnostics.XmlWriterTraceListener per restituire le tracce, è possibile passare un oggetto System.Xml.XPath.IXPathNavigable come oggetto dati a TraceData. La voce di tracciamento risultante include il codice XML fornito dal System.Xml.XPath.XPathNavigator. Di seguito è riportato un esempio di voce con dati dell'applicazione 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>  

Il visualizzatore di traccia WCF riconosce lo schema dell'elemento TraceRecord illustrato in precedenza ed estrae i dati dai relativi elementi figlio e lo visualizza in un formato tabulare. Il canale deve usare questo schema quando si tracciano dati dell'applicazione strutturati per consentire agli utenti di Svctraceviewer.exe leggere i dati.