What If There's No Error Handling?
Suppose I write a WCF web service with no try-catch blocks and no error handling. What happens when my web service throws an exception? Since I don't have any error handling, WCF catches the exception for me. It sends the client (the program that called my web service) a FaultException with the following message:
"The server was unable to process the request due to an internal error."
Whenever there's an unhandled exception, that's all the information the client gets. WCF doesn't send the client the exception message or the stack trace or any of the other information that was contained in the exception.
There are a number of reasons why WCF does this. One reason is that the Exception class is specific to .Net. WCF was designed to make web services that can be called by anyone, including clients that are not written in .Net. The client program can be written in Java or PHP or a variety of other languages. So WCF doesn't assume that the clients were written in .Net, and it doesn't send them .Net specific responses.
Another reason WCF doesn't send the client more information is that this might not be safe. It's not safe to provide the stack trace to anyone that may call. Detailed error messages are also risky. For example, it's not safe to inform the caller that the database insert failed because user name "andrew.fenster" is already in use. The safer practice is to write this information to an error log and provide much less detailed error information to the caller.
Providing More Information With FaultExceptions
A bare FaultException may be safe, but it doesn't provide enough information. I may not want to pass the full stack trace, but I want to provide at least basic information about what went wrong. WCF provides multiple ways to do this.
The FaultException class itself includes several ways to provide more information. The FaultException class includes these constructors (among others):
- public FaultException(string reason);
- public FaultException(string reason, FaultCode code);
- public FaultException(FaultReason reason);
- public FaultException(FaultReason reason, FaultCode code);
- try
- {
- // do something
- }
- catch (Exception ex)
- {
- myLogger.LogException(ex);
- throw new FaultException("Your request timed out. Please try again later.");
- }
- try
- {
- // call the web service
- }
- catch (FaultException ex)
- {
- Console.WriteLine(ex.Message);
- }
The FaultReason class lets you provide the same error message in multiple languages. If you look at the list of FaultException constructors, you will see that you can either provide an error message in a string or a collection of error messages in a FaultReason. You don't need both.
A FaultCode allows you to provide a code (a string) to tell the client what went wrong. For example:
- try
- {
- // do something
- }
- catch (Exception ex)
- {
- myLogger.LogException(ex);
- FaultCode code = new FaultCode("Invalid Operation");
- throw new FaultException("Customer name cannot be null.", code);
- }
- try
- {
- // call the web service
- }
- catch (FaultException ex)
- {
- Console.WriteLine("FaultCode: " + ex.Code);
- Console.WriteLine("Message: " + ex.Message);
- }
The FaultException<T> class
The FaultException class gives you several ways to inform the client about what went wrong. Sometimes, however, you may want more.
The FaultException<T> class is derived from the FaultException class. As with the FaultException class, you can pass in some combination of string, FaultCode and FaultReason. You can also pass in some additional value T. T can be a value or an entire class object. For example, you could define your own error class:
- [DataContract]
- public class ErrorMessage
- {
- private Guid ticketNumber;
- [DataMember]
- public Guid TicketNumber
- {
- get { return ticketNumber; }
- set { ticketNumber = value; }
- }
- [DataMember]
- public string Message
- {
- get { return "An error has occurred. For more information,
- call us and tell us your ticket number."; }
- } public ErrorMessage(Guid newTicket)
- {
- ticketNumber = newTicket;
- }
- }
- try
- {
- // Do something
- }
- catch (Exception ex)
- {
- Guid ticket = myLogger.LogException(ex);
- ErrorMessage message = new ErrorMessage(ticket);
- throw new FaultException<ErrorMessage>(message);
- }
- try
- {
- // call the web service
- }
- catch (FaultException<ErrorMessage> ex)
- {
- Guid ticket = ex.Detail.TicketNumber;
- string message = ex.Detail.Message;
- }
- public FaultException(T detail);
- public FaultException(T detail, string reason);
- public FaultException(T detail, FaultReason reason);
- public FaultException(T detail, string reason, FaultCode code);
- public FaultException(T detail, FaultReason reason, FaultCode code);
FaultContracts
If you are going to use the FaultException<T> class, you need to create a FaultContract. The FaultContract tells the client program what type of Faults each method can throw. For example:
- [ServiceContract]
- interface IMyService
- {
- [OperationContract]
- [FaultContract(typeof(ErrorMessage))]
- int DoSomething();
- }
You can specify more than one fault type. For example:
- [ServiceContract]
- interface IMyService
- {
- [OperationContract]
- [FaultContract(typeof(ErrorMessage))]
- [FaultContract(typeof(Guid))]
- int DoSomething();
- }
If a web service throws a FaultExeption<T> of a type not declared in the ServiceContract, it will not reach the client. For example, if the ServiceContract says I will throw a FaultException<ErrorMessage>, and my service instead throws a FaultException<string>, WCF will block my fault. Instead, it will send the client a bare FaultException with the generic message "The server was unable to process the request due to an internal error."
Best Practices
There are no shortage of people offering their own advice about error handling. I have only a few points to make.
First and most important, you should be very cautious about providing detailed information to the client about what went wrong. Most error details are either a security risk or simply irrelevant to the client. For example, the Stack Trace contains details about your code which should not be revealed. Even if the client is another division within your own company, they don't need you to send them the Stack Trace. If you sent them the Stack Trace, what would they do with it? Likewise, it's not a good idea to simply catch exceptions and pass the exception Message to the client.
There are only a few types of messages that the client may care about. For example, if the client did not provide a required field, informing the client might be useful. If the system is down temporarily, you could tell the client to try later. Error messages that reveal details about your code, however, don't help the client but do provide security risks.
Using an ErrorMessage class like the one shown above may be sufficient. The client is informed that something went wrong. It anyone needs more information, they can provide you with a ticket number, and you can look up the error in the error log.
One other suggestion: if you are going to provide any significant error information, it would be best to have a FaultContract. Even though the basic FaultException class allows you to pass a message and a FaultCode and a FaultReason (and a few other things not discussed in this article), it makes sense to forego these and use a FaultException<T>, with all your error information inside the detail object T. That way the client knows exactly what to expect and doesn't try reading a value from the FaultReason when there's no FaultReason provided.
In conclusion, WCF provides you with a lot of options for error handling. As long as you think carefully about what information you are providing and the format in which you provide it, you should come out fine.

Preguntón Cojonero CabrónPosted Sep 29, 2015, 3:16 PM
any good patterns and practices about it ? any good patterns and practices about it ? An example of handling errors at the client: try { proxy.SomeOperation(); } catch (FaultException<MyFaultInfo> ex) { // only if a fault contract was specified } catch (FaultException ex) { // any other faults } catch (CommunicationException ex) { // any communication errors? }
Milton SarmientoPosted Jan 24, 2012, 3:36 PM
I need this example for me to showme how functional is
Nuno GuerreiroPosted Nov 16, 2011, 1:54 PM
I have some REST services implemented via WCF Rest Starter Kit. When a service receives a request with invalid XML, say an invalid date in a datetime field, it immediately closes the http connection without returning any information to the calling client. I believe this is the default behavior for security purposes, but I'd like to change it a bit, to throw a generic error message, but I don't see how. I believe your examples don't work for this specific scenario, because I think the service implementation doesn't even get called! This is causing client applications (which run on mobile devices) to think that the network connection suddenly went down. Many thanks for any help. Regards, Nuno Guerreiro
Guest UserPosted May 11, 2011, 10:19 AM
The Message property of the ErrorMessage class needs a setter, or the sample code won't work and fail serialization.