We have been doing exception handling in managed application using try
-catch
block with Exception or its derived Custom Exception objects. But this mechanism is very much .NET Technology specific. When we develop SOA applications, our application is not limited to merely one technology or single loyal client. So the communication process of this service or service method level errors to client via wire becomes a little bit tricky. WCF has two types of error handling mechanisms: one is by as usual Exception objects, and the other is by SOAP fault message. SOAP fault is used to marshall .NET exceptions to client in much readable and convenient way to support interoperability. With use of SOAP fault, the verbose exception message is reduced to Code and Message. For this System.ServiceModel namespace
comes FaultException
class and FaultContract
attribute.
Let’s come to see from the example how to do exception handling in WCF application. Before this, write our service first.
namespace WcfSvc
{
[ServiceContract]
public interface IBasicMathService
{
[OperationContract]
int Subtraction(int x, int y);
[OperationContract]
int Multiplication(int x, int y);
[OperationContract]
[FaultContract(typeof(BasicMathFault))]
int Addition(int x, int y);
}
[DataContract]
public class BasicMathFault
{
[DataMember]
public string Source;
[DataMember]
public string ExceptionMessage;
[DataMember]
public string InnerException;
[DataMember]
public string StackTrace;
}
}
And its implementation is as:
public class BasicMath : IBasicMathService
{
public int Addition(int x, int y)
{
int result = 0;
try
{
result = (x + y);
}
catch
{
BasicMathFault ex = new BasicMathFault();
ex.Source = "BasicMath.Addition method";
ex.ExceptionMessage = "Could not perform addition operation.";
ex.InnerException = "Inner exception from math service";
ex.StackTrace = "";
throw new FaultException(ex, new FaultReason(
"This is an error condition in BasicMath.Addition method")); }
return result;
}
public int Multiplication(int x, int y)
{
throw new FaultException(new FaultReason(
"Error occurred while processing for the result"), new FaultCode(
"mutliplication.method.error"));
}
public int Subtraction(int x, int y)
{
throw new NotImplementedException("Method still not implemented");
}
}
This is our typical service related code. If we see IBasicMathService interface
and its implementation in BasicMath
class, we have: Addition(x,y)
method decorated with FaultContract
attribute in IBasicMathService
class, Subtraction(x,y)
method using simple Exception throwing mechanism, Multiplication(x,y)
method using simple FaultException
object, and Addition(x,y)
method using strongly-typed fault of type BasicMathFault
in FaultException
object.
So what does all this mean to the client, and how exception is transmitted to the client? Let’s answer with these three examples in our client code.
A) Throwing Simple Exception
private void SubtractIntegers()
{
try
{
obj = new BasicmathServiceRef.BasicMathServiceClient();
int result = obj.Subtraction(10, 15);
}
catch (Exception ex)
{
Response.Write(ex.Message + "
");
}
}
When this method is called, client receives verbose error message from WCF as: “The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults
(either from ServiceBehaviorAttribute
or from the configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.”
If we closely take a look at this error information, we come across two things: turn on\off IncludeExceptionDetailInFaults
value, either through ServiceBehaviorAttribute
of the class containing this method, or modify IncludeExceptionDetailInFaults
value in configuration file or section of this service.
Either of these two things is pretty easy.
a) Decorate BasicMath
class as:
[ServiceBehavior(IncludeExceptionDetailInFaults = false)]
public class BasicMath : IBasicMathService
{
b) Or, modify in config file:
By default, this key value is false
. If we make it true
, the verbose error message that we received will be reduced to human readable message that we passed in the constructor of NotImplementedException
. “Method still not implemented”
While debugging WCF exception, one may encounter error in the service like “xyz exception unhandled by user code”. This is somewhat misleading, but there is no need to worry.
B) Throw Exception of FaultException Type
private void MultiplyIntegers()
{
try
{
obj = new BasicmathServiceRef.BasicMathServiceClient();
int result = obj.Multiplication(10, 15);
}
catch (FaultException ex)
{
Response.Write(ex.Message + "
");
}
}
On calling this method, WCF will serialize the exception as a Fault message and return to the client as: “Error occurred while processing for the result”.
However, client is unlikely to receive verbose error message if we throw exception of type FaultException
even key IncludeExceptionDetailInFaults
is true
or false
. If we see the exception thrown code,
throw new FaultException(new FaultReason("Error occurred while processing for the result"),
new FaultCode("mutliplication.method.error"));
we have used FaultCode
. Client can use this specific fault code contained in FaultException
code to take a decision, but this approach becomes more of procedural by many if
-else
condition to branch out code something like:
if (ex.Code.Name == "mutliplication.method.error")
{
Response.Write(ex.Message + "
");
}
C) Throwing With Strongly Typed Fault
private void AddIntegers()
{
try
{
obj = new BasicmathServiceRef.BasicMathServiceClient();
int result = obj.Addition(10, 15);
}
catch (FaultException ex)
{
Response.Write(ex.Message + "
");
}
}
With this approach, the client will be able to explicitly handle fault of only that type whose service method is to be used by client. Here, we are using BasicMathFault
type. At the service level, the specific method has to be decorated with FaultContract
attribute so that exception can be serialized as:
[OperationContract]
[FaultContract(typeof(BasicMathFault))]
int Addition(int x, int y);
The detail of fault type is up to our convenient level to let WCF serialize only needful information to client.
When we call this Addition(x,y)
method, one may receive this error message if an exception occurs. “This is an error condition in BasicMath.Addition
method.”
Thus, we see how we can do exception handling in WCF.