Dela via


Mottagning och sändning av 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 kastar en ny System.ServiceModel.FaultException<TDetail> av typen GreetingFault med ett nytt GreetingFault objekt som argument, se 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. Generellt rekommenderas det att du använder egenskapen ServiceDebugBehavior.IncludeExceptionDetailInFaults när du felsöker. 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 det att man sätter ServiceBehaviorAttribute.IncludeExceptionDetailInFaults eller ServiceDebugBehavior.IncludeExceptionDetailInFaults till true endast som ett sätt att tillfälligt felsöka ett tjänstprogram. Dessutom innehåller WSDL för en metod som returnerar ohanterade undantag på det här sättet inte kontraktet för FaultException<TDetail> av 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 System.ServiceModel.FaultException undantag där strängen är tillgänglig genom att anropa metoden FaultException<TDetail>.ToString.

Anmärkning

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

Felhantering

I WCF-klienter genereras SOAP-fel under kommunikation, som är relevanta för klientapplikationer, 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 tvåvägsoperation (det vill säga en metod med ett attribut OperationContractAttribute där IsOneWay är satt till värdet false).

Anmärkning

När en WCF-tjänst har egenskapen ServiceBehaviorAttribute.IncludeExceptionDetailInFaults eller ServiceDebugBehavior.IncludeExceptionDetailInFaults inställda på true upplevs detta av klienten som en odeklarerad FaultException<TDetail> av typen 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.

Anmärkning

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 felundantag 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 när lokala objekt hanteras, 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, rekommenderas det då att man, förutom att fånga undantag i rätt ordning, också avbryter 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.

Anmärkning

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