Senden und Empfangen von Fehlern

SOAP-Fehler vermitteln Informationen über Fehlerbedingungen von einem Dienst an einen Client und bei Duplexkommunikation von einem Client an einen Dienst in einem interoperablen Verfahren. In der Regel definiert ein Dienst benutzerdefinierten Fehlerinhalt und legt fest, welche Vorgänge ihn zurückgeben können. (Weitere Informationen zu Definieren und Angeben von Fehlern.) In diesem Thema wird erläutert, wie ein Dienst oder ein Duplexclient diese Fehler senden kann, wenn der entsprechende Fehlerzustand aufgetreten ist, und wie eine Client- oder Dienstanwendung diese Fehler verarbeitet. Eine Übersicht über die Fehlerbehandlung in WCF-Anwendungen (Windows Communication Foundation) finden Sie unter Angeben und Behandeln von Fehlern in Verträgen und Diensten.

Senden von SOAP-Fehlern

Bei deklarierten SOAP-Fehlern verfügt ein Vorgang über ein System.ServiceModel.FaultContractAttribute, das einen benutzerdefinierten SOAP-Fehlertyp angibt. Nicht deklarierte SOAP-Fehler sind Fehler, die nicht im Vertrag eines Vorgangs festgelegt sind.

Senden von deklarierten Fehlern

Um einen deklarierten SOAP-Fehler zu senden, erkennen Sie die Fehlerbedingung, zu der der SOAP-Fehler passt, und lösen Sie eine neue System.ServiceModel.FaultException<TDetail> aus, bei der der Typparameter ein neues Objekt des Typs ist, der im FaultContractAttribute für diesen Vorgang angegeben ist. Im folgenden Codebeispiel wird veranschaulicht, wie mit dem FaultContractAttribute angegeben werden kann, dass der SampleMethod-Vorgang einen SOAP-Fehler mit dem Detailtyp GreetingFault zurückgeben kann.

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

Um die GreetingFault-Fehlerinformation an den Client zu übermitteln, fangen Sie die entsprechende Fehlerbedingung ab, und lösen Sie eine System.ServiceModel.FaultException<TDetail> vom Typ GreetingFault mit einem neuen GreetingFault-Objekt als Argument aus, wie im folgenden Codebeispiel dargestellt. Wenn es sich bei dem Client um eine WCF-Clientanwendung handelt, erfährt er dies als verwaltete Ausnahme, wobei der Typ eine System.ServiceModel.FaultException<TDetail> vom Typ GreetingFault ist.

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

Senden von undeklarierten Fehlern

Das Senden von undeklarierten Fehlern kann sehr nützlich sein, um Probleme in WCF-Anwendungen schnell zu diagnostizieren und zu debuggen, aber der Nutzen als Debugtool ist begrenzt. Allgemeiner gesagt, ist es empfehlenswert, beim Debuggen die ServiceDebugBehavior.IncludeExceptionDetailInFaults-Eigenschaft zu verwenden. Wenn Sie diesen Wert auf true festlegen, erfahren Clients solche Fehler als FaultException<TDetail>-Ausnahmen des Typs ExceptionDetail.

Wichtig

Da mit verwalteten Ausnahmen interne Anwendungsinformationen verfügbar gemacht werden können, kann mit der Festlegung von ServiceBehaviorAttribute.IncludeExceptionDetailInFaults oder ServiceDebugBehavior.IncludeExceptionDetailInFaults auf true WCF-Clients ermöglicht werden, Informationen über interne Dienstvorgangsausnahmen, einschließlich persönlich identifizierbarer oder anderer vertraulicher Informationen, abzurufen.

Daher wird die Festlegung von ServiceBehaviorAttribute.IncludeExceptionDetailInFaults für ServiceDebugBehavior.IncludeExceptionDetailInFaults oder true nur für das vorübergehende Debuggen einer Dienstanwendung empfohlen. Außerdem beinhaltet die WSDL für eine Methode, die nicht behandelte verwaltete Ausnahmen auf diese Weise zurückgibt, keinen Vertrag für die FaultException<TDetail> vom Typ ExceptionDetail. Clients müssen auf die Möglichkeit von unbekannten SOAP-Fehlern vorbereitet sein, die an WCF-Clients als System.ServiceModel.FaultException-Objekte zurückgegeben werden, damit sie die Debuginformationen korrekt abrufen können.

Um einen undeklarierten SOAP-Fehler zu senden, lösen Sie ein System.ServiceModel.FaultException-Objekt aus (d. h. nicht den generischen Typ FaultException<TDetail>), und übergeben Sie die Zeichenfolge dem Konstruktor. Dies wird für die WCF-Clientanwendungen als eine ausgelöste System.ServiceModel.FaultException-Ausnahme verfügbar gemacht, wobei die Zeichenfolge durch Aufrufen der FaultException<TDetail>.ToString-Methode verfügbar ist.

Hinweis

Wenn Sie einen SOAP-Fehler vom Typ Zeichenfolge deklarieren und dies dann in Ihrem Service als FaultException<TDetail> auslösen, wobei der Typparameter eine System.String ist, wird der Zeichenfolgenwert der FaultException<TDetail>.Detail-Eigenschaft zugewiesen und ist nicht über FaultException<TDetail>.ToString verfügbar.

Behandeln von Fehlern

Bei WCF-Clients werden während einer Kommunikation auftretende SOAP-Fehler, die für Clientanwendungen relevant sind, als verwaltete Ausnahmen ausgelöst. Während es viele Ausnahmen gibt, die während der Ausführung eines Programms auftreten können, können Anwendungen, die das Programmiermodell des WCF-Clients verwenden, Ausnahmen der beiden folgenden Typen als Kommunikationsergebnis behandeln.

TimeoutException-Objekte werden ausgelöst, wenn ein Vorgang das angegebene Zeitlimit überschreitet.

CommunicationException-Objekte werden ausgelöst, wenn entweder beim Dienst oder beim Client eine behebbare Kommunikationsfehlerbedingung besteht.

Die CommunicationException-Klasse verfügt über zwei wichtige abgeleitete Typen: FaultException und den generischen FaultException<TDetail>-Typ.

FaultException-Ausnahmen werden ausgelöst, wenn ein Listener einen Fehler empfängt, der in dem Vorgangsvertrag nicht erwartet oder festgelegt ist; dies geschieht normalerweise, wenn die Anwendung gedebuggt wird und die ServiceDebugBehavior.IncludeExceptionDetailInFaults-Eigenschaft des Diensts auf true festgelegt ist.

Am Client werden FaultException<TDetail>-Ausnahmen ausgelöst, wenn ein im Vorgangsvertrag angegebener Fehler als Antwort auf einen bidirektionalen Vorgang empfangen wird (d. h. eine Methode mit einem OperationContractAttribute-Attribut, bei dem IsOneWay auf false festgelegt ist).

Hinweis

Wenn für einen WCF-Dienst die ServiceBehaviorAttribute.IncludeExceptionDetailInFaults- oder die ServiceDebugBehavior.IncludeExceptionDetailInFaults-Eigenschaft auf true festgelegt ist, erfährt der Client dies als eine undeklarierte FaultException<TDetail> vom Typ ExceptionDetail. Clients können diesen bestimmten Fehler entweder abfangen oder den Fehler in einem Catch-Block für FaultException behandeln.

In der Regel sind nur FaultException<TDetail>-, TimeoutException- und CommunicationException-Ausnahmen für Clients und Dienste relevant.

Hinweis

Es treten natürlich andere Ausnahmen auf. Unerwartete Ausnahmen schließen schwerwiegende Fehler wie System.OutOfMemoryException ein; in der Regel sollten Anwendungen solche Methoden nicht abfangen.

Abfangen von Fehlerausnahmen in der richtigen Reihenfolge

Da FaultException<TDetail> von FaultException abgeleitet wird und FaultException von CommunicationException abgeleitet wird, müssen diese Ausnahmen in der richtigen Reihenfolge abgefangen werden. Bei einem try/catch-Block, bei dem zuerst CommunicationException abgefangen wird, werden z. B. alle angegebenen und nicht angegebenen SOAP-Fehler dort behandelt; nachfolgende catch-Blöcke zum Behandeln einer benutzerdefinierten FaultException<TDetail>-Ausnahme werden niemals aufgerufen.

Vergessen Sie nicht, dass ein Vorgang eine beliebige Anzahl angegebener Fehler zurückgeben kann. Jeder Fehler ist ein eindeutiger Typ und muss getrennt behandelt werden.

Behandeln von Ausnahmen beim Schließen des Kanals

Der größte Teil der vorangehenden Erläuterung behandelt Fehler, die während der Verarbeitung von Anwendungsnachrichten gesendet werden, d. h. Nachrichten, die explizit vom Client gesendet werden, wenn die Clientanwendung Vorgänge für das WCF-Clientobjekt aufruft.

Sogar lokale Objekte, die das Objekt verwerfen, können Ausnahmen, die während des Wiederverwendungsprozesses auftreten, entweder auslösen oder maskieren. Etwas Ähnliches kann auftreten, wenn Sie WCF-Clientobjekte verwenden. Wenn Sie Vorgänge aufrufen, senden Sie Nachrichten über eine hergestellte Verbindung. Das Schließen des Kanals kann Ausnahmen auslösen, wenn die Verbindung nicht ordnungsgemäß getrennt wird oder bereits getrennt ist, selbst wenn alle Vorgänge ordnungsgemäß zurückgegeben werden.

In der Regel werden Clientobjektkanäle auf eine der folgenden Möglichkeiten geschlossen:

  • Wenn das WCF-Clientobjekt wiederverwendet wird.

  • Wenn die Clientanwendung ClientBase<TChannel>.Close aufruft.

  • Wenn die Clientanwendung ICommunicationObject.Close aufruft.

  • Wenn die Clientanwendung einen Vorgang aufruft, bei dem es sich um einen Vorgang handelt, der eine Sitzung beendet.

In jedem Fall weist das Schließen des Kanals den Kanal an zu beginnen, alle zugrunde liegenden Kanäle zu schließen, die möglicherweise Nachrichten senden, um eine komplexe Funktionalität auf Anwendungsebene zu unterstützen. Wenn z. B. ein Vertrag Sitzungen erfordert, versucht eine Bindung eine Sitzung einzurichten, indem Nachrichten mit dem Dienstkanal ausgetauscht werden, bis eine Sitzung eingerichtet ist. Wenn der Kanal geschlossen wird, benachrichtigt der zugrunde liegende Sitzungskanal den Dienst, dass die Sitzung beendet wird. Wenn der Kanal bereits abgebrochen oder geschlossen ist oder aus anderen Gründen nicht verwendet werden kann (z. B. wenn ein Netzwerkkabel abgezogen wird), kann der Clientkanal dem Dienstkanal in diesem Fall nicht mitteilen, dass die Sitzung beendet wird, und dies kann zu einer Ausnahme führen.

Abbrechen des Kanals (falls erforderlich)

Da das Schließen des Kanals auch Ausnahmen auslösen kann, wird empfohlen, den Kanal, der für den Aufruf in dem catch-Block verwendet wurde, zusätzlich zum Abfangen von Fehlerausnahmen in der richtigen Reihenfolge abzubrechen.

Wenn der Fehler Fehlerinformationen übermittelt, die für einen Vorgang spezifisch sind, und andere ihn möglicherweise verwenden können, muss der Kanal nicht abgebrochen werden (obwohl dies selten vorkommt). In allen anderen Fällen wird empfohlen, den Kanal abzubrechen. Eine Beispielanwendung, die all dies veranschaulicht, finden Sie unter Erwartete Ausnahmen.

Das folgende Codebeispiel veranschaulicht die Behandlung von SOAP-Fehlerausnahmen in einer grundlegenden Clientanwendung einschließlich eines deklarierten Fehlers und eines undeklarierten Fehlers.

Hinweis

Dieser Beispielcode verwendet kein using-Konstrukt. Da das Schließen von Kanälen Ausnahmen auslösen kann, ist es empfehlenswert, dass Anwendungen zuerst einen WCF-Client erstellen und dann den WCF-Client im selben try-Block öffnen, verwenden und schließen. Ausführliche Informationen finden Sie unter Übersicht über den WCF-Client und Freigeben von WCF-Clientressourcen mit „Close“ und „Abort“.

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

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

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

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

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

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

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

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

Siehe auch