Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Ausnahmen werden verwendet, um Fehler lokal innerhalb des Diensts oder der Clientimplementierung zu kommunizieren. Fehler werden dagegen verwendet, um Fehler über Dienstgrenzen hinweg zu kommunizieren, z. B. vom Server zum Client oder umgekehrt. Neben Fehlern verwenden Transportkanäle häufig transportspezifische Mechanismen, um Fehler auf Transportebene zu kommunizieren. Beispielsweise verwendet der HTTP-Transport Statuscodes wie 404, um eine nicht vorhandene Endpunkt-URL zu kommunizieren (es gibt keinen Endpunkt, der einen Fehler zurücksendet). Dieses Dokument besteht aus drei Abschnitten, die Anleitungen für benutzerdefinierte Kanalautoren bereitstellen. Der erste Abschnitt enthält Anleitungen zum Definieren und Auslösen von Ausnahmen. Der zweite Abschnitt enthält Anleitungen zum Generieren und Verarbeiten von Fehlern. Im dritten Abschnitt wird erläutert, wie Sie Ablaufverfolgungsinformationen bereitstellen, um den Benutzer Ihres benutzerdefinierten Kanals bei der Problembehandlung bei der Ausführung von Anwendungen zu unterstützen.
Ausnahmen
Beim Auslösen einer Ausnahme müssen zwei Dinge beachtet werden: Zunächst muss es sich um einen Typ handeln, mit dem Benutzer korrekten Code schreiben können, der entsprechend auf die Ausnahme reagieren kann. Zweitens muss der Benutzer genügend Informationen bereitstellen, um zu verstehen, was schief gelaufen ist, welche Fehler sich auswirken und wie man es beheben kann. Die folgenden Abschnitte enthalten Anleitungen zu Ausnahmetypen und Nachrichten für Windows Communication Foundation (WCF)-Kanäle. Es gibt auch allgemeine Anleitungen zu Ausnahmen in .NET im Dokument "Entwurfsrichtlinien für Ausnahmen".
Ausnahmetypen
Alle von Kanälen ausgelösten Ausnahmen müssen entweder ein System.TimeoutException, ein System.ServiceModel.CommunicationException oder ein Typ sein, der von CommunicationException abgeleitet ist. (Ausnahmen wie ObjectDisposedException z. B. können auch ausgelöst werden, aber nur um anzugeben, dass der aufrufende Code den Kanal missbraucht hat. Wenn ein Kanal richtig verwendet wird, darf er nur die angegebenen Ausnahmen auslösen.) WCF stellt sieben Ausnahmetypen bereit, die von CommunicationException Kanälen abgeleitet und verwendet werden sollen. Es gibt andere CommunicationExceptionabgeleitete Ausnahmen, die von anderen Teilen des Systems verwendet werden sollen. Diese Ausnahmetypen sind:
| Ausnahmetyp | Bedeutung | Innerer Ausnahmeinhalt | Wiederherstellungsstrategie |
|---|---|---|---|
| AddressAlreadyInUseException | Die für das Abhören angegebene Endpunktadresse wird bereits verwendet. | Wenn vorhanden, finden Sie weitere Details zu dem Transportfehler, der diese Ausnahme verursacht hat. Beispiel: PipeException, HttpListenerException oder SocketException. | Probieren Sie eine andere Adresse aus. |
| AddressAccessDeniedException | Der Prozess darf nicht auf die für das Abhören angegebene Endpunktadresse zugreifen. | Wenn vorhanden, finden Sie weitere Details zu dem Transportfehler, der diese Ausnahme verursacht hat. Beispiel: PipeException oder HttpListenerException. | Versuchen Sie es mit anderen Anmeldeinformationen. |
| CommunicationObjectFaultedException | Das verwendete ICommunicationObject befindet sich im Zustand "Fehlerhaft" (weitere Informationen finden Sie unter Grundlegendes zu Statusänderungen). Beachten Sie, dass beim Übergang eines Objekts mit mehreren ausstehenden Aufrufen zum Fehlerhaften Zustand nur ein Aufruf eine Ausnahme auslöst, die sich auf den Fehler bezieht, und der Rest der Aufrufe löst eine Ausnahme CommunicationObjectFaultedExceptionaus. Diese Ausnahme wird in der Regel ausgelöst, da eine Anwendung eine Ausnahme übersieht und versucht, ein bereits fehlerhaftes Objekt zu verwenden, möglicherweise in einem anderen Thread als dem, der die ursprüngliche Ausnahme erfasst hat. | Gibt, sofern vorhanden, Details zur inneren Ausnahme an. | Erstellen eines neuen Objekt. Beachten Sie, dass je nachdem, was den ICommunicationObject-Fehler verursacht hat, möglicherweise weitere Maßnahmen erforderlich sein könnten, um eine Wiederherstellung zu ermöglichen. |
| CommunicationObjectAbortedException | Das verwendete ICommunicationObject wurde abgebrochen (weitere Informationen finden Sie unter Understanding State Changes (Informationen zu Statusänderungen)). Ähnlich wie CommunicationObjectFaultedExceptiondiese Ausnahme gibt an, dass die Anwendung das Objekt aufgerufen Abort hat, möglicherweise aus einem anderen Thread, und das Objekt ist aus diesem Grund nicht mehr verwendbar. | Gibt, sofern vorhanden, Details zur inneren Ausnahme an. | Erstellen eines neuen Objekt. Beachten Sie, dass je nachdem, was den Abbruch von ICommunicationObject ursprünglich verursacht hat, weitere Maßnahmen zur Problembehandlung erforderlich sein können. |
| EndpointNotFoundException | Der Remotezielendpunkt führt keine Überwachung aus. Dies kann dazu führen, dass jeder Teil der Endpunktadresse falsch, unlösbar oder der Endpunkt abwesend ist. Beispiele sind DNS-Fehler, Warteschlangen-Manager nicht verfügbar und der Dienst wird nicht ausgeführt. | Die innere Ausnahme enthält Details, in der Regel aus dem zugrunde liegenden Transport. | Probieren Sie eine andere Adresse aus. Alternativ kann der Absender eine Weile warten und es erneut versuchen, falls der Dienst ausgefallen war. |
| ProtocolException | Die Kommunikationsprotokolle, wie durch die Richtlinie des Endpunkts beschrieben, sind zwischen Endpunkten nicht übereinstimmend. Beispiele: Rahmeninhaltstypenkonflikt oder die maximale Nachrichtengröße wurde überschritten. | Wenn vorhanden, werden weitere Informationen zum spezifischen Protokollfehler bereitgestellt. Zum Beispiel ist QuotaExceededException die innere Ausnahme, wenn die Ursache des Fehlers darin besteht, dass die MaxReceivedMessageSize überschritten wird. | Wiederherstellung: Stellen Sie sicher, dass absender- und empfangene Protokolleinstellungen übereinstimmen. Eine Möglichkeit hierzu besteht darin, die Metadaten (Richtlinie) des Dienstendpunkts erneut zu importieren und die generierte Bindung zu verwenden, um den Kanal neu zu erstellen. |
| ServerTooBusyException | Der Remoteendpunkt empfängt, ist aber nicht auf die Verarbeitung von Nachrichten vorbereitet. | Wenn vorhanden, stellt die innere Ausnahmebedingung die Details des SOAP-Fehlers oder des Transportfehlers bereit. | Wiederherstellung: Warten Sie, und wiederholen Sie den Vorgang später. |
| TimeoutException | Der Vorgang konnte nicht innerhalb des Timeoutzeitraums abgeschlossen werden. | Stellt möglicherweise Details über das Timeout bereit. | Warten Sie, und wiederholen Sie den Vorgang später. |
Definieren Sie einen neuen Ausnahmetyp nur, wenn dieser Typ einer bestimmten Wiederherstellungsstrategie entspricht, die sich von allen vorhandenen Ausnahmetypen unterscheidet. Wenn Sie einen neuen Ausnahmetyp definieren, muss er von CommunicationException oder einer der abgeleiteten Klassen abgeleitet werden.
Ausnahmemeldungen
Ausnahmemeldungen sind auf den Benutzer ausgerichtet, nicht auf das Programm, sodass er ausreichende Informationen bereitstellen sollte, um dem Benutzer zu helfen, das Problem zu verstehen und zu lösen. Eine gute Ausnahmemeldung besteht im Wesentlichen aus den folgenden drei Teilen:
Was ist passiert. Stellen Sie eine klare Beschreibung des Problems mithilfe von Begriffen bereit, die sich auf die Benutzererfahrung beziehen. Beispielsweise wäre eine ungültige Ausnahmemeldung "Ungültiger Konfigurationsabschnitt". Dadurch fragt sich der Benutzer, welcher Konfigurationsabschnitt falsch ist und warum er falsch ist. Eine verbesserte Meldung wäre "Ungültiger Konfigurationsabschnitt <customBinding>". Eine noch bessere Nachricht wäre "Der Transport mit dem Namen "myTransport" kann der Bindung mit dem Namen "myBinding" nicht hinzugefügt werden, da die Bindung bereits einen Transport mit dem Namen "myTransport" aufweist. Dies ist eine sehr spezifische Nachricht mit Begriffen und Namen, die der Benutzer in der Konfigurationsdatei der Anwendung leicht identifizieren kann. Es fehlen jedoch noch einige wichtige Komponenten.
Die Bedeutung des Fehlers. Sofern die Meldung nicht eindeutig angibt, was der Fehler bedeutet, fragt sich der Benutzer wahrscheinlich, ob es sich um einen schwerwiegenden Fehler handelt oder ob er ignoriert werden kann. Im Allgemeinen sollten Nachrichten mit der Bedeutung oder Wichtigkeit des Fehlers beginnen. Um das vorherige Beispiel zu verbessern, könnte die Meldung "ServiceHost konnte aufgrund eines Konfigurationsfehlers nicht geöffnet werden: Der Transport mit dem Namen "myTransport" kann nicht zur Bindung mit dem Namen "myBinding" hinzugefügt werden, da die Bindung bereits einen Transport mit dem Namen "myTransport" aufweist.
Wie der Benutzer das Problem beheben sollte. Der wichtigste Teil der Nachricht ist, dem Benutzer bei der Problemlösung zu helfen. Die Nachricht sollte einige Anleitungen oder Hinweise dazu enthalten, was überprüft oder behoben werden soll, um das Problem zu beheben. Beispiel: "ServiceHost konnte aufgrund eines Konfigurationsfehlers nicht geöffnet werden: Der Transport mit dem Namen "myTransport" kann der Bindung mit dem Namen "myBinding" nicht hinzugefügt werden, da die Bindung bereits einen Transport mit dem Namen "myTransport" aufweist. Stellen Sie sicher, dass die Bindung nur einen Transport enthält.“
Kommunizieren von Fehlern
SOAP 1.1 und SOAP 1.2 definieren beide eine bestimmte Struktur für Fehler. Es gibt einige Unterschiede zwischen den beiden Spezifikationen, aber im Allgemeinen werden die Typen "Message" und "MessageFault" verwendet, um Fehler zu erstellen und zu nutzen.
SOAP 1.2-Fehler (links) und SOAP 1.1-Fehler (rechts). In SOAP 1.1 ist nur das Fault-Element namespacefähig.
SOAP definiert eine Fehlermeldung als eine Nachricht, die nur ein Fehlerelement (ein Element mit dem Namen <env:Fault>) als untergeordnetes Element von <env:Body> enthält. Der Inhalt des Fehlerelements unterscheidet sich geringfügig zwischen SOAP 1.1 und SOAP 1.2, wie in Abbildung 1 dargestellt. Die System.ServiceModel.Channels.MessageFault Klasse normalisiert diese Unterschiede jedoch in einem Objektmodell:
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
}
Die Code Eigenschaft entspricht dem env:Code (oder faultCode in SOAP 1.1) und identifiziert den Typ des Fehlers. SOAP 1.2 definiert fünf zulässige Werte für faultCode (z. B. Sender und Receiver) und definiert ein Subcode Element, das einen beliebigen Untercodewert enthalten kann. (Die SOAP 1.2-Spezifikation für die Liste der zulässigen Fehlercodes und deren Bedeutung finden Sie in der SOAP 1.2-Spezifikation .) SOAP 1.1 weist einen etwas anderen Mechanismus auf: Es definiert vier faultCode Werte (z. B. Client und Server), die entweder durch Definieren vollständig neuer Werte oder durch Verwenden der Punktnotation erweitert werden können, um spezifischere faultCodesWerte zu erstellen, z. B. "Client.Authentication".
Wenn Sie MessageFault zum Programmieren von Fehlern verwenden, ist FaultCode.Name und FaultCode.Namespace dem Namen und Namespace von SOAP 1.2 env:Code oder SOAP 1.1 faultCode zugeordnet. FaultCode.SubCode wird env:Subcode für SOAP 1.2 zugeordnet und ist für SOAP 1.1 NULL.
Sie sollten neue Fehleruntercodes (oder neue Fehlercodes bei Verwendung von SOAP 1.1) erstellen, wenn es interessant ist, einen Fehler programmgesteuert zu unterscheiden. Dies entspricht dem Erstellen eines neuen Ausnahmetyps. Vermeiden Sie die Verwendung der Punktnotation mit SOAP 1.1-Fehlercodes. (Das WS-I Basic Profile rät auch von der Verwendung der Punktnotation für Fehlercodes ab.)
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
}
Die Reason Eigenschaft entspricht der env:Reason (oder faultString in SOAP 1.1) einer lesbaren Beschreibung der Fehlerbedingung analog zur Meldung einer Ausnahme. Die FaultReason Klasse (und SOAP env:Reason/faultString) bietet integrierte Unterstützung für mehrere Übersetzungen im Interesse der Globalisierung.
public class FaultReason
{
public FaultReason(FaultReasonText translation);
public FaultReason(IEnumerable<FaultReasonText> translations);
public FaultReason(string text);
public SynchronizedReadOnlyCollection<FaultReasonText> Translations
{
get;
}
}
Der Inhalt der Fehlerdetails wird für „MessageFault“ mit verschiedenen Methoden verfügbar gemacht, einschließlich GetDetail<T> und GetReaderAtDetailContents(). Das Fehlerdetail ist ein undurchsichtiges Element zum Bereitstellen zusätzlicher Details über den Fehler. Dies ist nützlich, wenn Sie ein beliebiges strukturiertes Detail mit dem Fehler mitführen möchten.
Generieren von Fehlern
In diesem Abschnitt wird der Prozess der Generierung eines Fehlers als Reaktion auf eine fehlerbedingung erläutert, die in einem Kanal oder in einer vom Kanal erstellten Nachrichteneigenschaft erkannt wurde. Ein typisches Beispiel ist das Senden eines Fehlers als Reaktion auf eine Anforderungsnachricht, die ungültige Daten enthält.
Beim Generieren eines Fehlers sollte der benutzerdefinierte Kanal den Fehler nicht direkt senden, sondern es sollte eine Ausnahme auslösen und die obige Ebene entscheiden lassen, ob diese Ausnahme in einen Fehler konvertiert und wie sie gesendet werden soll. Um diese Konvertierung zu unterstützen, sollte der Kanal eine FaultConverter Implementierung bereitstellen, die die vom benutzerdefinierten Kanal ausgelöste Ausnahme in den entsprechenden Fehler konvertieren kann.
FaultConverter ist definiert als:
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);
}
Jeder Kanal, der benutzerdefinierte Fehler generiert, muss FaultConverter implementieren und nach einem Aufruf von GetProperty<FaultConverter> zurückgeben. Die benutzerdefinierte OnTryCreateFaultMessage Implementierung muss entweder die Ausnahme in einen Fehler konvertieren oder an den inneren FaultConverterKanal delegieren. Wenn es sich um einen Transportkanal handelt, muss der Kanal die Ausnahme konvertieren oder an den FaultConverter des Encoders oder den standardmäßigen FaultConverter von WCF delegieren.
FaultConverter Standardmäßig werden Fehler konvertiert, die den von WS-Addressing und SOAP angegebenen Fehlermeldungen entsprechen. Im Folgenden sehen Sie ein Beispiel für eine OnTryCreateFaultMessage-Implementierung.
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
}
Eine Auswirkung dieses Musters ist, dass Ausnahmen, die zwischen Ebenen für Fehlerbedingungen ausgelöst werden, die Fehler erfordern, genügend Informationen für den entsprechenden Fehlergenerator enthalten müssen, um den richtigen Fehler zu erstellen. Als benutzerdefinierter Kanalautor können Sie Ausnahmetypen definieren, die unterschiedlichen Fehlerbedingungen entsprechen, wenn solche Ausnahmen noch nicht vorhanden sind. Beachten Sie, dass Ausnahmen, die Kanalschichten durchlaufen, eher die Fehlerbedingung statt der nicht transparenten Fehlerdaten übermitteln sollten.
Fehlerkategorien
Im Allgemeinen gibt es drei Kategorien von Fehlern:
Fehler, die den gesamten Stack durchdringen. Diese Fehler können auf jeder Ebene im Kanalstapel auftreten, z. B. InvalidCardinalityAddressingException.
Fehler, die an einer beliebigen Stelle über einer bestimmten Ebene im Stapel auftreten können, z. B. einige Fehler, die zu einer flussierten Transaktion oder zu Sicherheitsrollen gehören.
Fehler, die auf eine einzige Schicht im Stack gerichtet sind, zum Beispiel Fehler wie WS-RM-Sequenznummernfehler.
Kategorie 1. Fehler sind im Allgemeinen WS-Addressing und SOAP-Fehler. Die von WCF bereitgestellte Basisklasse FaultConverter konvertiert Fehler, die den von WS-Addressing und SOAP angegebenen Fehlermeldungen entsprechen, sodass Sie die Konvertierung dieser Ausnahmen selbst nicht verarbeiten müssen.
Kategorie 2. Fehler treten auf, wenn eine Schicht der Nachricht eine Eigenschaft hinzufügt, die die zu dieser Schicht gehörenden Nachrichteninformationen nicht vollständig umsetzt. Fehler werden möglicherweise später erkannt, wenn eine höhere Schicht von der Eigenschaft eine weitere Verarbeitung von Nachrichteninformationen verlangt. Solche Kanäle sollten das zuvor angegebene GetProperty implementieren, damit die höhere Ebene den korrekten Fehler zurücksenden kann. Ein Beispiel hierfür ist die TransactionMessageProperty. Diese Eigenschaft wird der Nachricht hinzugefügt, ohne alle Daten in der Kopfzeile vollständig zu validieren (dies kann eine Kontaktaufnahme mit dem Koordinator für verteilte Transaktionen (DTC) erforderlich machen).
Kategorie 3. Fehler werden nur von einer einzelnen Ebene im Prozessor generiert und gesendet. Daher sind alle Ausnahmen innerhalb der Ebene enthalten. Um die Konsistenz zwischen den Kanälen zu verbessern und die Wartung zu vereinfachen, sollte Ihr benutzerdefinierter Kanal das zuvor angegebene Muster verwenden, um Fehlermeldungen auch bei internen Fehlern zu generieren.
Empfangene Fehler interpretieren
Dieser Abschnitt enthält Anleitungen zum Generieren der entsprechenden Ausnahme beim Empfang einer Fehlermeldung. Die Entscheidungsstruktur für die Verarbeitung einer Nachricht auf jeder Ebene im Stapel lautet wie folgt:
Wenn die Ebene die Nachricht als ungültig betrachtet, sollte die Ebene die Verarbeitung der "ungültigen Nachricht" ausführen. Diese Verarbeitung hängt von der jeweiligen Schicht ab, kann jedoch das Verwerfen der Meldung, eine Ablaufverfolgung oder das Auslösen einer Ausnahme beinhalten, die in einen Fehler konvertiert wird. Beispiele hierfür sind der Sicherheitsdienst, der eine Nachricht erhält, die nicht ordnungsgemäß gesichert ist, oder RM, die eine Nachricht mit einer ungültigen Sequenznummer erhält.
Andernfalls, wenn es sich bei der Nachricht um eine Fehlermeldung handelt, die speziell auf die Schicht zutrifft und die Nachricht außerhalb der Interaktion der Schicht nicht aussagekräftig ist, sollte die Schicht die Fehlerbedingung selbst behandeln. Ein Beispiel hierfür ist ein Fehler aufgrund einer abgelehnten RM-Sequenz. Dieser Fehler ist für die Schichten über dem RM-Kanal bedeutungslos und impliziert, dass der RM-Kanal einen Fehler ausgibt und ausstehende Vorgänge eine Ausnahme auslösen.
Andernfalls sollte die Meldung von Request() oder Receive() zurückgegeben werden. Dazu gehören Fälle, in denen die Schicht den Fehler erkennt, der Fehler jedoch nur angibt, dass eine Anforderung fehlgeschlagen ist. Dabei impliziert der Fehler nicht, dass der RM-Kanal einen Fehler ausgibt und ausstehende Vorgänge eine Ausnahme auslösen. Um die Benutzerfreundlichkeit in einem solchen Fall zu verbessern, sollte die Ebene
GetProperty<FaultConverter>implementieren und eineFaultConverterabgeleitete Klasse zurückgeben, die den Fehler durch Außerkraftsetzung vonOnTryCreateExceptionin eine Ausnahme konvertieren kann.
Das folgende Objektmodell unterstützt das Konvertieren von Nachrichten in Ausnahmen:
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);
}
Eine Kanalschicht kann GetProperty<FaultConverter> implementieren, um Fehlermeldungen in Ausnahmen umzuwandeln. Setzen Sie dazu OnTryCreateException außer Kraft, und überprüfen Sie die Fehlermeldung. Falls erkannt, führen Sie die Konvertierung aus, andernfalls bitten Sie den inneren Kanal, ihn zu konvertieren. Transportkanäle sollten eine Delegierung an FaultConverter.GetDefaultFaultConverter ausführen, um den standardmäßigen FaultConverter der SOAP/WS-Adressierung abzurufen.
Eine typische Implementierung sieht wie folgt aus:
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
}
Für bestimmte Fehlerzustände, die unterschiedliche Wiederherstellungsszenarien erfordern, sollten Sie eine abgeleitete Klasse von ProtocolException definieren.
Verarbeitung von MustUnderstand
SOAP definiert einen allgemeinen Fehler, wenn ein erforderlicher Header vom Empfänger nicht interpretiert werden konnte. Dieser Fehler wird als mustUnderstand Fehler bezeichnet. In WCF generieren mustUnderstand benutzerdefinierte Kanäle nie Fehler. Stattdessen überprüft der WCF Dispatcher, der sich oben im WCF-Kommunikationsstapel befindet, um festzustellen, ob alle Header, die als MustUnderstand=true gekennzeichnet wurden, vom zugrunde liegenden Stapel verstanden wurden. Wenn sie nicht verstanden wurden, wird zu diesem Zeitpunkt ein mustUnderstand Fehler generiert. (Der Benutzer kann diese mustUnderstand Verarbeitung deaktivieren und die Anwendung erhält alle Nachrichtenkopfzeilen. In diesem Fall ist die Anwendung für die Verarbeitung mustUnderstand verantwortlich.) Der generierte Fehler enthält einen NotUnderstood-Header, der die Namen aller Kopfzeilen mit MustUnderstand=true enthält, die nicht verstanden wurden.
Wenn Ihr Protokollkanal einen benutzerdefinierten Header mit MustUnderstand=true sendet und einen mustUnderstand Fehler empfängt, muss ermittelt werden, ob dieser Fehler auf den gesendeten Header zurückzuführen ist. Die MessageFault-Klasse besitzt zwei Member, die für diesen Zweck nützlich sind:
public class MessageFault
{
...
public bool IsMustUnderstandFault { get; }
public static bool WasHeaderNotUnderstood(MessageHeaders headers,
string name, string ns) { }
...
}
IsMustUnderstandFault gibt zurück true , wenn der Fehler ein mustUnderstand Fehler ist.
WasHeaderNotUnderstood gibt true zurück, wenn der Header mit dem angegebenen Namen und Namespace im Fehler als NotUnderstood-Header enthalten ist. Andernfalls wird falsezurückgegeben.
Wenn ein Kanal einen Header ausgibt, der als MustUnderstand = true gekennzeichnet ist, sollte diese Ebene auch das API-Muster zur Ausnahmegenerierung implementieren und Fehler, die durch diesen Header verursacht werden, mustUnderstand in eine nützlichere Ausnahme konvertieren, wie zuvor beschrieben.
Nachverfolgung
.NET Framework bietet einen Mechanismus zum Nachverfolgen der Programmausführung als Möglichkeit zur Diagnose von Produktionsanwendungen oder zeitweiligen Problemen, bei denen es nicht möglich ist, nur einen Debugger anzufügen und den Code schrittweise durchzugehen. Die Kernkomponenten dieses Mechanismus befinden sich im System.Diagnostics Namespace und bestehen aus:
System.Diagnostics.TraceSource stellt die Quelle der zu schreibenden Anlaufverfolgungsinformationen dar, System.Diagnostics.TraceListener, stellt die abstrakte Basisklasse für konkrete Listener dar, die zu verfolgende Informationen von TraceSource erhalten und an ein für die Listener spezifisches Ziel ausgeben. Beispielsweise gibt XmlWriterTraceListener Ablaufverfolgungsinformationen in eine XML-Datei aus. System.Diagnostics.TraceSwitch wird in der Konfiguration angegeben und ermöglicht dem Benutzer der Anwendung die Ausführlichkeit der Ablaufverfolgung zu steuern.
Zusätzlich zu den Kernkomponenten können Sie das Dienstablaufverfolgungs-Viewer-Tool (SvcTraceViewer.exe) verwenden, um WCF-Ablaufverfolgungen anzuzeigen und zu durchsuchen. Das Tool wurde speziell für Ablaufverfolgungsdateien entwickelt, die in WCF generiert und mit XmlWriterTraceListener geschrieben werden. Die folgende Abbildung zeigt die verschiedenen Komponenten der Ablaufverfolgung.
Ablaufverfolgung durch einen benutzerdefinierten Kanal
Als Hilfestellung bei der Diagnose von Problemen, bei denen es nicht möglich ist, der laufenden Anwendung einen Debugger hinzuzufügen, sollten benutzerdefinierte Kanäle Ablaufverfolgungsmeldungen ausgeben. Das schließt zwei komplexe Aufgaben ein: Instanziieren einer TraceSource und Aufrufen ihrer Methoden zu Schreiben von Ablaufverfolgungen.
Beim Instanziieren einer TraceSource wird die von Ihnen angegebene Zeichenfolge zum Namen dieser Quelle. Mit diesem Namen wird die Ablaufverfolgungsquelle konfiguriert (Aktivieren/Deaktivieren/Festlegen der Ablaufverfolgungsebene). Der Name wird außerdem direkt in der Ausgabe der Ablaufverfolgung angegeben. Benutzerdefinierte Kanäle sollten einen eindeutigen Quellennamen verwenden, damit Leser der Ablaufverfolgungsausgabe erkennen können, woher die Ablaufverfolgungsinformationen stammen. Im Allgemeinen wird als Name der Ablaufverfolgungsquelle der Name der Assembly verwendet, die diese Informationen schreibt. Zum Beispiel verwendet WCF „System.ServiceModel“ als Ablaufverfolgungsquelle für Informationen, die von der System.ServiceModel-Assembly geschrieben werden.
Sobald eine Ablaufverfolgungsquelle vorhanden ist, rufen Sie ihre Methoden TraceDataTraceEvent oder TraceInformation auf, um Ablaufverfolgungseinträge für den Ablaufverfolgungslistener zu schreiben. Für jeden von Ihnen geschriebenen Ablaufverfolgungseintrag müssen Sie den Ereignistyp als einen der Ereignistypen klassifizieren, die in TraceEventType definiert sind. Diese Klassifikation und die Einstellung der Ablaufverfolgungsebene in der Konfiguration bestimmen, ob der Ablaufverfolgungseintrag an den Listener ausgegeben wird. Wenn z. B. die Ablaufverfolgungsebene in der Konfiguration auf Warning festgelegt wird, können Warning- Error- und Critical-Ablaufverfolgungsereignisse geschrieben werden, Information- und Verbose-Einträge werden jedoch blockiert. Das folgende Beispiel veranschaulicht die Instanziierung einer Ablaufverfolgungsquelle und das Schreiben eines Eintrags auf Information-Ebene:
using System.Diagnostics;
//...
TraceSource udpSource = new TraceSource("Microsoft.Samples.Udp");
//...
udpsource.TraceInformation("UdpInputChannel received a message");
Von Bedeutung
Geben Sie unbedingt einen Namen für die Ablaufverfolgungsquellen an, der in Ihren benutzerdefinierten Kanal eindeutig ist, damit Leser der Ablaufverfolgungsausgabe erkennen können, woher die Ausgabe stammt.
Integration des Ablaufverfolgungs-Viewers
Von Ihrem Kanal generierte Ablaufverfolgungen können in einem Format ausgegeben werden, das vom Service Trace Viewer Tool (SvcTraceViewer.exe) gelesen werden kann, indem System.Diagnostics.XmlWriterTraceListener als Ablaufverfolgungslistener verwendet wird. Dies ist nichts, was Sie als Kanalentwickler tun müssen. Dieser Ablaufverfolgungslistener muss eher von den Benutzer*innen der Anwendung (oder der Person, die Anwendungsprobleme behandelt) in der Konfigurationsdatei der Anwendung konfiguriert werden. Die folgende Konfiguration gibt beispielsweise sowohl Verfolgungsinformationen von System.ServiceModel als auch von Microsoft.Samples.Udp in die Datei mit dem Namen TraceEventsFile.e2e aus.
<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>
Nachverfolgen strukturierter Daten
System.Diagnostics.TraceSource verfügt über eine TraceData Methode, die ein oder mehrere Objekte übernimmt, die in den Trace-Eintrag einbezogen werden sollen. Im Allgemeinen wird die Object.ToString Methode für jedes Objekt aufgerufen, und die resultierende Zeichenfolge wird als Teil des Protokolleintrags geschrieben. Wenn Sie System.Diagnostics.XmlWriterTraceListener verwenden, um Ablauffolgen auszugeben, können Sie ein System.Xml.XPath.IXPathNavigable als Datenobjekt an TraceData übergeben. Der resultierende Ablaufverfolgungseintrag schließt die von System.Xml.XPath.XPathNavigator bereitgestellten XML-Daten ein. Hier ist ein Beispieleintrag mit XML-Anwendungsdaten:
<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>
Der WCF-Ablaufverfolgungs-Viewer versteht das Schema des zuvor gezeigten TraceRecord-Elements, extrahiert die Daten aus dessen untergeordneten Elementen und zeigt sie in tabellarischer Form an. Ihr Kanal sollte dieses Schema verwenden, wenn strukturierte Anwendungsdaten nachverfolgt werden, damit Svctraceviewer.exe Benutzer die Daten lesen können.