Ready to have some fun… Today I spent the day investigating WCF FaulContracts and FaultException and some best practices for argument validation. I’m going to do the same in a future post on Workflow Services but I felt it best to really understand the topic from a WCF point of view first.
"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 <serviceDebug> 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."
No surprises here, probably anyone who has done WCF for more than 5 minutes has run into this. For more information see the WCF documentation Sending and Receiving Faults. You might be tempted to just turn on IncludeExceptionDetailInFaults but don’t do it because it can lead to security vulnerabilities. Instead you need a better strategy for dealing with exceptions and that means you need to understand FaultException
As we saw in the previous example, WCF already throws a FaultException for you when it encounters an unhandled exception. The problem is in this case that we want to let the caller know they sent an invalid argument even when they are not debugging.
public string GetDataFaultException(int data)
{
if (data < 0)
// Let the sender know it is their problem
var faultCode =
FaultCodeFactory.CreateVersionAwareSenderFaultCode(
ContractFaultCodes.InvalidArgument.ToString(), ContractConstants.Namespace);
var faultReason = string.Format(Resources.ValueOutOfRange, "Data", Resources.ValueGreaterThanZero);
throw new FaultException(faultReason, faultCode);
}
return "Data: " + data;
The main thing is that the client now gets a message saying that things didn’t work and its their fault. They can tell by looking at the FaultException.Code.IsSenderFault property. In my code you’ll notice a class I created called CreateVersionAwareSenderFaultCode to help deal with the differences between SOAP 1.1 and SOAP 1.2. You will find it in the sample.
Some interesting things I learned while testing this
While this is better than throwing unhandled exceptions, there is an even better way and that is FaultContracts
var argValidationFault = new ArgumentValidationFault
ArgumentName = "Data",
Message = string.Format(Resources.ValueOutOfRange, "Data", Resources.ValueGreaterThanZero),
HelpLink = GetAbsoluteUriHelpLink("DataHelp.aspx"),
};
throw new FaultException<ArgumentValidationFault>(argValidationFault, argValidationFault.Message, faultCode);
This is the best choice. It allows you to pass all kinds of information to clients and it makes your error handling capability truly first class. In the sample code one thing I wanted to do was to use the FaultException.HelpLink property to pass a Url to a help page. Unfortunately I learned that none of System.Exception’s properties are propagated to the sender. No problem, I just added a HelpLink property to my ArgumentValidationFault type and used it instead in FaultException.Details.HelpLink
Use [FaultContract] on your service operations. You should probably create a base type for your details and perhaps have a few subclasses for special categories of things. Remember that whatever you expose in the FaultContract is part of your public API and that versioning considerations that apply to other DataContracts apply to your faults as well.
Happy Coding!
Ron http://blogs.msdn.com/rjacobs Twitter: @ronljacobs