Hibák küldése és fogadása
A SOAP-hibák egy szolgáltatásból egy ügyfélnek, kétoldalas esetben pedig egy szolgáltatásba továbbítják a hibaállapot-információkat egymással együttműködő módon. A szolgáltatás általában egyéni hibatartalmakat határoz meg, és meghatározza, hogy mely műveletek adhatják vissza őket. (További információ: Hibák meghatározása és megadása.) Ez a témakör azt ismerteti, hogy egy szolgáltatás- vagy kétoldalas ügyfél hogyan küldheti el ezeket a hibákat a megfelelő hibaállapot bekövetkezésekor, és hogy egy ügyfél vagy szolgáltatásalkalmazás hogyan kezeli ezeket a hibákat. A Windows Communication Foundation (WCF) alkalmazások hibakezelésének áttekintéséért lásd: Szerződések és szolgáltatások hibáinak megadása és kezelése.
SOAP-hibák küldése
A deklarált SOAP-hibák azok, amelyekben egy művelet System.ServiceModel.FaultContractAttribute egyéni SOAP-hibatípust határoz meg. A be nem jelentett SOAP-hibák azok, amelyek nincsenek megadva a műveletre vonatkozó szerződésben.
Deklarált hibák küldése
Deklarált SOAP-hiba küldéséhez észlelje a SOAP-hiba megfelelő hibafeltételét, és küldjön egy újat System.ServiceModel.FaultException<TDetail> , ahol a típusparaméter az adott műveletben FaultContractAttribute megadott típus új objektuma. Az alábbi példakód azt mutatja be, hogy a FaultContractAttribute művelet képes-e SampleMethod
SOAP-hibát visszaadni a részletek típusával 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
Ha a GreetingFault
hibainformációkat az ügyfélnek szeretné továbbítani, a megfelelő hibafeltételt kell elkapnia, és argumentumként egy új System.ServiceModel.FaultException<TDetail> típusú GreetingFault
típust kell megadnia egy új GreetingFault
objektummal, ahogyan az alábbi kódpéldában is látható. Ha az ügyfél WCF-ügyfélalkalmazás, ezt felügyelt kivételként tapasztalja, ahol a típus System.ServiceModel.FaultException<TDetail> típusa 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
Be nem jelentett hibák küldése
A be nem jelentett hibák küldése nagyon hasznos lehet a WCF-alkalmazások problémáinak gyors diagnosztizálásához és hibakereséséhez, de a hibakeresési eszköz hasznossága korlátozott. Általánosságban elmondható, hogy hibakereséskor ajánlott a ServiceDebugBehavior.IncludeExceptionDetailInFaults tulajdonságot használni. Ha igaz értékre állítja ezt az értéket, az ügyfelek olyan hibákat tapasztalnak, mint a FaultException<TDetail> típus ExceptionDetailkivételei.
Fontos
Mivel a felügyelt kivételek közzétehetik a belső alkalmazásadatokat, beállíthatják ServiceBehaviorAttribute.IncludeExceptionDetailInFaults vagy ServiceDebugBehavior.IncludeExceptionDetailInFaults engedélyezhetik, hogy true
a WCF-ügyfelek információt szerezzenek a belső szolgáltatásműveleti kivételekről, beleértve a személyazonosításra alkalmas vagy más bizalmas információkat is.
Ezért a beállítás vagy ServiceDebugBehavior.IncludeExceptionDetailInFaults a beállítás ServiceBehaviorAttribute.IncludeExceptionDetailInFaultstrue
csak a szolgáltatásalkalmazások ideiglenes hibakeresésének módjaként javasolt. Ezenkívül egy olyan metódus WSDL-értéke, amely így kezeletlen felügyelt kivételeket ad vissza, nem tartalmazza a FaultException<TDetail> típus szerződését ExceptionDetail. Az ügyfeleknek egy ismeretlen SOAP-hiba (a WCF-ügyfeleknek objektumként System.ServiceModel.FaultException visszaadott) lehetőségére kell számítaniuk a hibakeresési információk megfelelő beszerzéséhez.
Ha be nem jelentett SOAP-hibát szeretne küldeni, dobjon egy System.ServiceModel.FaultException objektumot (vagyis ne az általános típust FaultException<TDetail>), és adja át a sztringet a konstruktornak. Ez kivételként System.ServiceModel.FaultException jelenik meg a WCF-ügyfélalkalmazások számára, ahol a sztring elérhető a FaultException<TDetail>.ToString metódus meghívásával.
Feljegyzés
Ha sztring típusú SOAP-hibát deklarál, majd ezt a szolgáltatásban olyanként FaultException<TDetail> adja meg, ahol a típusparaméter a tulajdonsághoz rendelt sztringérték System.String , és nem érhető el a FaultException<TDetail>.Detail tulajdonságból FaultException<TDetail>.ToString.
Hibák kezelése
A WCF-ügyfelek esetében az ügyfélalkalmazások számára érdekes kommunikáció során előforduló SOAP-hibák felügyelt kivételként jelennek meg. Bár számos kivétel fordulhat elő bármely program végrehajtása során, a WCF-ügyfélprogramozási modellt használó alkalmazások a kommunikáció eredményeként az alábbi két típus kivételeinek kezelésére számíthatnak.
TimeoutException objektumokat dobnak, ha egy művelet túllépi a megadott időtúllépési időtartamot.
CommunicationException az objektumok akkor jelennek meg, ha valamilyen helyreállítható kommunikációs hiba van a szolgáltatáson vagy az ügyfélen.
Az CommunicationException osztály két fontos származtatott típussal FaultException és általános típussal FaultException<TDetail> rendelkezik.
FaultException kivételek akkor keletkeznek, ha a figyelő olyan hibát kap, amely nem várható vagy nem szerepel a műveleti szerződésben; általában ez akkor fordul elő, ha az alkalmazás hibakeresése folyamatban van, és a szolgáltatás tulajdonsága a ServiceDebugBehavior.IncludeExceptionDetailInFaults következőre true
van állítva: .
FaultException<TDetail> a rendszer kivételeket alkalmaz az ügyfélre, ha a műveleti szerződésben meghatározott hiba kétirányú műveletre (azaz egy olyan metódusra) reagál, amelynek OperationContractAttribute az attribútuma IsOneWay a következőre false
van állítva: ).
Feljegyzés
Ha egy WCF-szolgáltatás rendelkezik az ServiceBehaviorAttribute.IncludeExceptionDetailInFaults ügyfélre true
beállított tulajdonságtal, ServiceDebugBehavior.IncludeExceptionDetailInFaults ez be nem jelentett típusként ExceptionDetailjelenik megFaultException<TDetail>. Az ügyfelek elkaphatják ezt az adott hibát, vagy kezelhetik a hibát egy fogási blokkban a következőhöz FaultException: .
Általában csak FaultException<TDetail>a , TimeoutExceptionés CommunicationException a kivételek érdeklik az ügyfeleket és a szolgáltatásokat.
Feljegyzés
Természetesen más kivételek is előfordulnak. A váratlan kivételek közé tartoznak az olyan katasztrofális hibák, mint például System.OutOfMemoryException; az alkalmazások általában nem kapják el az ilyen módszereket.
Hiba kivételeinek fogása a helyes sorrendben
Mivel FaultException<TDetail> származik FaultException, és FaultException származik CommunicationException, fontos, hogy elfogja ezeket a kivételeket a megfelelő sorrendben. Ha például van egy próba-/fogási blokkja, amelyben először elkapja CommunicationException, az összes megadott és meghatározatlan SOAP-hiba ott lesz kezelve; az egyéni FaultException<TDetail> kivétel kezelésére szolgáló további fogási blokkok soha nem lesznek meghívva.
Ne feledje, hogy egy művelet bármilyen számú megadott hibát visszaadhat. Minden hiba egyedi típus, és külön kell kezelni.
Kivételek kezelése a csatorna bezárásakor
Az előző vitafórumok többségének az alkalmazásüzenetek feldolgozása során küldött hibákkal, azaz az ügyfél által explicit módon küldött üzenetekkel kell kapcsolatosnak kell szerepelnie, amikor az ügyfélalkalmazás műveleteket hív meg a WCF-ügyfélobjektumon.
Az újrahasznosítási folyamat során fellépő kivételeket még a helyi objektumok is feloldhatják vagy maszkolhatják. Hasonló dolog fordulhat elő WCF-ügyfélobjektumok használatakor. Amikor meghívja a műveleteket, egy létrehozott kapcsolaton keresztül küld üzeneteket. A csatorna bezárása kivételeket okozhat, ha a kapcsolat nem zárható le vagy már lezárva van, még akkor is, ha az összes művelet megfelelően visszaadott.
Az ügyfélobjektum-csatornák általában az alábbi módok egyikével vannak lezárva:
A WCF-ügyfélobjektum újrafeldolgozásakor.
Amikor az ügyfélalkalmazás hív ClientBase<TChannel>.Close.
Amikor az ügyfélalkalmazás hív ICommunicationObject.Close.
Amikor az ügyfélalkalmazás olyan műveletet hív meg, amely egy munkamenet megszakítási művelete.
A csatorna bezárása minden esetben arra utasítja a csatornát, hogy kezdje el bezárni azokat a mögöttes csatornákat, amelyek üzeneteket küldhetnek az alkalmazás szintjén az összetett funkciók támogatásához. Ha például egy szerződés munkameneteket igényel, kötési kísérlet egy munkamenet létrehozására úgy, hogy üzeneteket cserél a szolgáltatáscsatornával, amíg létre nem jön egy munkamenet. A csatorna bezárásakor a mögöttes munkamenetcsatorna értesíti a szolgáltatást, hogy a munkamenet le van állítva. Ebben az esetben, ha a csatorna már megszakadt, bezárult, vagy egyébként használhatatlan (például hálózati kábel leválasztásakor), az ügyfélcsatorna nem tudja értesíteni a szolgáltatáscsatornát arról, hogy a munkamenet leállt, és kivételt eredményezhet.
Szükség esetén megszakítja a csatornát
Mivel a csatorna bezárása kivételeket is okozhat, ezért a hibakivüldő kivételek helyes sorrendben történő elfogása mellett fontos megszakítani a híváshoz használt csatornát a fogási blokkban.
Ha a hiba egy adott műveletre vonatkozó hibainformációkat ad át, és továbbra is lehetséges, hogy mások is használhatják, nincs szükség a csatorna megszakítására (bár ezek az esetek ritkák). Minden más esetben javasoljuk, hogy megszakítsa a csatornát. Az összes pontot bemutató minta esetében lásd a várt kivételeket.
Az alábbi példakód bemutatja, hogyan kezelhetők a SOAP-hibák kivételei egy alapszintű ügyfélalkalmazásban, beleértve a deklarált hibát és a be nem jelentett hibát.
Feljegyzés
Ez a mintakód nem használja a szerkezetet using
. Mivel a bezárt csatornák kivételeket okozhatnak, javasoljuk, hogy az alkalmazások először hozzon létre EGY WCF-ügyfelet, majd nyissa meg, használja és zárja be a WCF-ügyfelet ugyanabban a kipróbálási blokkban. További részletekért tekintse meg a WCF-ügyfél áttekintését , valamint a WCF-ügyfélerőforrások kiadásához a Bezárás és megszakítás használata lehetőséget.
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