Dela via


Skicka och ta emot fel

SOAP-fel förmedlar information om feltillstånd från en tjänst till en klient och i duplex-fallet från en klient till en tjänst på ett driftskompatibelt sätt. Vanligtvis definierar en tjänst anpassat felinnehåll och anger vilka åtgärder som kan returnera dem. (Mer information finns i Definiera och ange fel.) I det här avsnittet beskrivs hur en tjänst- eller duplex-klient kan skicka dessa fel när motsvarande feltillstånd har inträffat och hur ett klient- eller tjänstprogram hanterar dessa fel. En översikt över felhantering i WCF-program (Windows Communication Foundation) finns i Ange och hantera fel i kontrakt och tjänster.

Skicka SOAP-fel

Deklarerade SOAP-fel är de där en åtgärd har en System.ServiceModel.FaultContractAttribute som anger en anpassad SOAP-feltyp. Odeklarerade SOAP-fel är de som inte anges i kontraktet för en åtgärd.

Skicka deklarerade fel

Om du vill skicka ett deklarerat SOAP-fel identifierar du feltillståndet för vilket SOAP-felet är lämpligt och genererar ett nytt System.ServiceModel.FaultException<TDetail> där typparametern är ett nytt objekt av den typ som anges i för den FaultContractAttribute åtgärden. Följande kodexempel visar användningen av FaultContractAttribute för att ange att SampleMethod åtgärden kan returnera ett SOAP-fel med detaljtypen GreetingFault.

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

Om du vill förmedla GreetingFault felinformationen till klienten fångar du rätt felvillkor och genererar en ny System.ServiceModel.FaultException<TDetail> typ GreetingFault med ett nytt GreetingFault objekt som argument, som i följande kodexempel. Om klienten är ett WCF-klientprogram fungerar det som ett hanterat undantag där typen är System.ServiceModel.FaultException<TDetail> av typen GreetingFault.

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

Skicka odeklarerade fel

Att skicka odeklarerade fel kan vara mycket användbart för att snabbt diagnostisera och felsöka problem i WCF-program, men dess användbarhet som felsökningsverktyg är begränsad. Mer allmänt rekommenderar vi att du använder egenskapen när du felsöker den ServiceDebugBehavior.IncludeExceptionDetailInFaults . När du anger det här värdet till sant uppstår sådana fel som FaultException<TDetail> undantag av typen ExceptionDetail.

Viktigt!

Eftersom hanterade undantag kan exponera intern programinformation, kan inställning ServiceBehaviorAttribute.IncludeExceptionDetailInFaults eller ServiceDebugBehavior.IncludeExceptionDetailInFaults till true tillåta WCF-klienter att hämta information om interna tjänståtgärdsfel, inklusive personligt identifierbar eller annan känslig information.

Därför rekommenderas inställning ServiceBehaviorAttribute.IncludeExceptionDetailInFaults eller ServiceDebugBehavior.IncludeExceptionDetailInFaults till endast som ett sätt att true tillfälligt felsöka ett tjänstprogram. Dessutom innehåller WSDL för en metod som returnerar ohanterade hanterade undantag på det här sättet inte kontraktet för FaultException<TDetail> typen ExceptionDetail. Klienter måste förvänta sig risken för ett okänt SOAP-fel (returneras till WCF-klienter som System.ServiceModel.FaultException objekt) för att få felsökningsinformationen korrekt.

Om du vill skicka ett odeklarerat SOAP-fel genererar du ett System.ServiceModel.FaultException objekt (dvs. inte den generiska typen FaultException<TDetail>) och skickar strängen till konstruktorn. Detta exponeras för WCF-klientprogrammen som ett undantag System.ServiceModel.FaultException där strängen är tillgänglig genom att anropa FaultException<TDetail>.ToString metoden.

Kommentar

Om du deklarerar ett SOAP-fel av typen sträng och sedan genererar detta i din tjänst som en FaultException<TDetail> där typparametern är ett System.String strängvärde tilldelas till FaultException<TDetail>.Detail egenskapen och är inte tillgängligt från FaultException<TDetail>.ToString.

Hantera fel

I WCF-klienter genereras SOAP-fel som inträffar under kommunikation som är av intresse för klientprogram som hanterade undantag. Det finns många undantag som kan inträffa under körningen av alla program, men program som använder WCF-klientprogrammeringsmodellen kan förvänta sig att hantera undantag av följande två typer som ett resultat av kommunikationen.

TimeoutException objekt utlöses när en åtgärd överskrider den angivna tidsgränsen.

CommunicationException objekt utlöses när det finns ett återställningsbart kommunikationsfel på antingen tjänsten eller klienten.

Klassen CommunicationException har två viktiga härledda typer FaultException och den generiska FaultException<TDetail> typen.

FaultException undantag utlöses när en lyssnare får ett fel som inte förväntas eller anges i åtgärdskontraktet. detta inträffar vanligtvis när programmet debuggas och tjänsten har ServiceDebugBehavior.IncludeExceptionDetailInFaults egenskapen inställd på true.

FaultException<TDetail> undantag utlöses på klienten när ett fel som anges i åtgärdskontraktet tas emot som svar på en dubbelriktad åtgärd (d.s. en metod med ett OperationContractAttribute attribut med IsOneWay värdet false).

Kommentar

När en WCF-tjänst har ServiceBehaviorAttribute.IncludeExceptionDetailInFaults egenskapen eller ServiceDebugBehavior.IncludeExceptionDetailInFaults inställd på true klienten används detta som en odeklarerad FaultException<TDetail> typ ExceptionDetail. Klienter kan antingen fånga det här specifika felet eller hantera felet i ett catch-block för FaultException.

Vanligtvis är endast FaultException<TDetail>, TimeoutExceptionoch CommunicationException undantag av intresse för klienter och tjänster.

Kommentar

Andra undantag inträffar naturligtvis. Oväntade undantag inkluderar katastrofala fel som System.OutOfMemoryException. Vanligtvis bör program inte fånga sådana metoder.

Fånga felfel i rätt ordning

Eftersom FaultException<TDetail> härleds från FaultException, och FaultException härleds från CommunicationException, är det viktigt att fånga dessa undantag i rätt ordning. Om du till exempel har ett try/catch-block där du först fångar CommunicationException, hanteras alla angivna och ospecificerade SOAP-fel där. Eventuella efterföljande fångstblock för att hantera ett anpassat FaultException<TDetail> undantag anropas aldrig.

Kom ihåg att en åtgärd kan returnera valfritt antal angivna fel. Varje fel är en unik typ och måste hanteras separat.

Hantera undantag när du stänger kanalen

Det mesta av föregående diskussion har att göra med fel som skickas under bearbetningen av programmeddelanden, dvs. meddelanden som uttryckligen skickas av klienten när klientprogrammet anropar åtgärder på WCF-klientobjektet.

Även om lokala objekt exponerar objektet kan det antingen generera eller maskera undantag som inträffar under återvinningsprocessen. Något liknande kan inträffa när du använder WCF-klientobjekt. När du anropar åtgärder skickar du meddelanden via en upprättad anslutning. Att stänga kanalen kan utlösa undantag om anslutningen inte kan stängas eller redan är stängd, även om alla åtgärder returneras korrekt.

Vanligtvis stängs klientobjektkanaler på något av följande sätt:

I samtliga fall instruerar stängning av kanalen kanalen att börja stänga alla underliggande kanaler som kan skicka meddelanden för att stödja komplexa funktioner på programnivå. När ett kontrakt till exempel kräver sessioner försöker en bindning upprätta en session genom att utbyta meddelanden med tjänstkanalen tills en session har upprättats. När kanalen stängs meddelar den underliggande sessionskanalen tjänsten att sessionen avslutas. I det här fallet, om kanalen redan har avbrutits, stängts eller på annat sätt är oanvändbar (till exempel när en nätverkskabel är urkopplad), kan klientkanalen inte informera tjänstkanalen om att sessionen har avslutats och ett undantag kan uppstå.

Avbryt kanalen om det behövs

Eftersom stängning av kanalen också kan utlösa undantag rekommenderar vi att du förutom att fånga fel undantag i rätt ordning, är det viktigt att avbryta den kanal som användes för att göra anropet i catch-blocket.

Om felet förmedlar felinformation som är specifik för en åtgärd och det fortfarande är möjligt att andra kan använda den, behöver du inte avbryta kanalen (även om dessa fall är sällsynta). I alla andra fall rekommenderar vi att du avbryter kanalen. Ett exempel som visar alla dessa punkter finns i Förväntade undantag.

I följande kodexempel visas hur du hanterar SOAP-fel i ett grundläggande klientprogram, inklusive ett deklarerat fel och ett odeklarerat fel.

Kommentar

Den här exempelkoden använder inte konstruktionen using . Eftersom stänga kanaler kan utlösa undantag rekommenderar vi att program skapar en WCF-klient först och sedan öppnar, använder och stänger WCF-klienten i samma försöksblock. Mer information finns i Översikt över WCF-klienten och Använd Stäng och Avbryt för att frigöra WCF-klientresurser.

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

Se även