WCF pro začátečníky – 5. díl: ošetření chyb na straně služby pomocí FaultContract
autor Kryštof Laryš
| publikováno 20. března 2010
V dnešním díle vám ukážu dva z postupů, jak docílit toho, aby služba jednoduše ošetřila výjimku, která nastane, a zprávu s chybou následně odeslala klientské aplikaci. K tomu slouží FaultContract atribut.
Na straně služby vytvoříme jednoduchou metodu, která nám spočítá faktoriál čísla, které zadáme v klientské aplikaci. Rozhodli jsme se, že pokud číslo odeslané na službu bude menší než 0, vyvoláme výjimku a zašleme ji klientovi. Kód bychom tedy ošetřili například tímto způsobem:
if (value2 < 0)
{
var faultCode = new FaultCode("Error");
MessageFault messageFault = MessageFault.CreateFault(faultCode, "Value must be greater than zero.");
throw new FaultException(messageFault);
}
Kde faultCode je proměnná s názvem chybového kódu třídy FaultCode. Pomocí nové instance MessageFault a její metody CreateFault vytvoříme z chybového kódu a chybové hlášky samotnou chybu, kterou budeme chtít odeslat klientské aplikaci. Nakonec vyvoláme výjimku FaultException, která se zašle klientské aplikaci.
Na straně klientské aplikace musíme tuto výjimku ošetřit, protože jinak bychom ji nemohli odchytit. To již probíhá jako klasické odchytávání chyb.
try
{
Console.Write("Write number to compute factorial: ");
Console.WriteLine(proxy.Factorial(Console.ReadLine()));
}
catch (FaultException exc)
{
Console.WriteLine(exc.Message);
}
V případě vyvolání výjimky se nám do klientské aplikace vypíše chybové hlášení: Value must be greater than zero.
Druhá a podle mého názoru také lepší možnost je použití generického typu výjimky FaultContract. Můžeme totiž lépe přizpůsobovat a strukturovat samotnou chybovou hlášku pomocí DataContract atributů.
Na straně služby ale musíme udělat několik málo úprav navíc oproti předchozímu příkladu. V definici rozhraní služby musíme dané metodě přiřadit atribut FaultContract a sdělit mu, jaký typ bude přesně vyvolávat. V našem případě je to:
[OperationContract]
[FaultContract(typeof(MyException))]
string Factorial2(object value);
Kde typ MyException jsme si definovali jako vlastní DataContract.
[DataContract]
public class MyException
{
[DataMember]
public string ExceptionMessage;
[DataMember]
public string ExceptionTitle;
}
Ten si můžeme libovolně dále upravovat. Část kódu na službě, který tuto výjimku vyvolává, se změnil jen mírně.
if (value2 < 0)
{
var cf = new MyException
{
ExceptionMessage = "Value must be greater than zero.",
ExceptionTitle = "Error"
};
throw new FaultException<MyException>(cf, cf.ExceptionTitle);
}
Kde cf je klasická instance naší vlastní třídy, kterou jsme si naplnili potřebnými daty. V našem případě pouze řetězci s chybovou hláškou a pojmenováním chyby. Výjimku jsme nakonec vyvolali s generickým typem MyException, kde nám jako parametry slouží samotná chyba (její text) a její nadpis, tedy důvod nebo kód chyby.
Na straně klientské aplikace musíme opět tuto výjimku ošetřit.
try
{
Console.Write("\n\nWrite number to compute factorial: ");
Console.WriteLine(proxy.Factorial2(Console.ReadLine()));
}
catch (FaultException<MyException> exc)
{
Console.WriteLine("{0}: {1}", exc.Detail.ExceptionTitle, exc.Detail.ExceptionMessage);
}
Zde vidíme, že se k chybovým hláškám přistupuje přes detaily, tedy vlastnost Detail vyvolané výjimky.
Snad vám tento díl pomohl k pochopení odesílání výjimek ze služby na klientskou aplikaci. Pokud chcete vidět příklad z jiného úhlu pohledu, přímo z MSDN, naleznete jej například zde:
http://msdn.microsoft.com/en-us/library/system.servicemodel.faultcontractattribute.aspx
Jedná se ale prakticky o totéž.
Zdrojové kódy ošetření chyb na straně služby pomocí FaultContract.
Kryštof