I recently read a old post on http://www.techinterviews.com containing interview questions for C# developers. One questions goes: ”Why is it a bad idea to throw your own exceptions?” And the answer is “Well, if at that point you know that an error has occurred, then why not write the proper code to handle that error instead of passing a new Exception object to the catch block? Throwing your own exceptions signifies some design flaws in the project.”
Now, there is a importance difference between knowing that an exception occured, and knowing enough to be able to write the proper code to handle the exception.
Handling exception in WCF services
This is especially true when working with WCF services. WCF services requires special care regarding exception handling. This is because exception normally are not allowed to be passed through a WCF channel. Instead WCF uses SOAP fault messages to pass exceptions.
Fault messages are part of the the SOAP specifications: A SOAP fault is a piece of XML within the SOAP envelope, that includes elements like a fault reason and code and a detail element that can contain custom XML. The layout of fault messages differs some between SOAP 1.1. and 1.2, but WCF hiddes these differences. (You can however interact with the fault message directly using the MessageFault
class). And most important: SOAP faults are platform independent.
A simplified SOAP 1.2. fault message could looks like this:
<?xml version='1.0' ?> <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:rpc='http://www.w3.org/2003/05/soap-rpc'> <env:Body> <env:Fault> <env:Code> <env:Value>10</env:Value> </env:Code> <env:Reason> <env:Text xml:lang="en-US">Error reason</env:Text> </env:Reason> <env:Detail> <e:FaultDetails xmlns:e="http:// example.org/faultsdetails"> <e:Description>Exception thrown</e: Description> <e:Occured>999</e:Occured> </e:FaultDetails> </env:Detail> </env:Fault> </env:Body> <env:Envelope>
WCF encapsulates the SOAP fault message in the FaultException
, located in the System.ServiceModel namespace
. The FaultException
comes in two flavors: A non-generic version, contains the basic fault message elements Action
, Code
and Reason
as properties, as well as the properties inherit from System.Exception
.
Beside this simple version, WCF also ships with a generic version FaultException
, that takes a instance of a custom class, and serializes it to the detail element of the fault message using the DataContractSerializer. This of cause requires that FaultDetails
is DataContract serializable, and the operation that may throw e.g. a FaultException<FaultDetails>
to marked with the FaultContract
attribute: Here my FaultDetail
class includes two properties, a timestamp and a description (the constructor is overloaded, so that FaultReason
and FaultCode
can be specified as well):
[OperationContract] [FaultContract(FaultDetails)] public void ThrowException() { throw new FaultException(new FaultDetails {Occured = DateTime.Now, Description = "Exception thrown"})); }
This exception can be caught on the client side:
[OperationContract] catch (FaultException fault) { Console.WriteLine(String.Format("{0}: {1}", fault.Detail.Occured, fault.Detail.Description); }
Fault exceptions over the wire
The point with the FaultExceptions are can be send over the WCF channel as SOAP to the client. Should any other CLR exception ever reach the WCF channel, WCF will instead send a general FaultException to the client. But this has some side effects: Besides from sending a general FaultException
, WCF will also kill the session (all WCF bindings except BasicHttpBinding
are sessionbased), and put the calling client in faulted state, meaning the the client will have to reconnect!
Including exception details in the fault exception
The generalt fault message emitted by WCF do not include details about the server side exception. This can be enabled on by marking the service with: [ServiceBehavior(IncludeExceptionDetailInFaults=true)]
. This means that WCF will now include the exception details in a FaultException instance. This behavior somewhat mimics the normal (WinForm) way of exception handling: A unhandled exception, the application gets killed, and the user gets the exception details. Like all debugging information, the ExceptionDetails may include stuff that the client should not know about. Therefore ExceptionDetails should only be included in debugging scenarios.
Throwing you own fault exceptions
A much better approach is to catch the exception before it reaches the channel, and retrown a FaultException
. Lets say that we actually know enough to be able to safely handle the exception, and we do not want to end the session and fault the client. If e.g. the exception indicates something like say a invalid parameter in a service operation call, I may want to handle the exception on the server, and then send an exception to the client (instead of returning some custom ”error” result, that the client then has to actively interpret).
Of course, the post on techinterviews.com clearly dates back before WCF. But it still holds that that one should also never try to handle a exception unless you are sure that you have the information needed. This is especially true in layered code, whether its server-client code like WCF or multi-tier.