As a software architect I tend to work on a lot of frameworks and low level code that I hand off to developers. My main goal when design a framework is to make the usability as simple as possible. I try to isolate my developers away from boilerplate code so they can spend more time working on business requirements. A common part of any application or web service is exception handling. A good exception handling framework can catch both expected and unexpected exceptions. I know… how would you know if it’s unexpected. Well the idea is to catch everything! Be a defensive designer when it comes to your frameworks. Expect that anything can go wrong with the users code, and I’m pretty sure it will.
Windows Communication Foundation has a nice provider model that allows developers to customize the behaviors of their services. One feature out of the box that you can implement in WCF is Exception Handling with implementing the IErrorHandler interface. IErrorHandler controls the fault message returned to the client and gives your application an options to perform custom exception handling routines.
Covered in this example:
IErrorHandler Overview
The following code below illustrates the implementation of the IErrorHandler Interface. There are two general methods that control the whole thing. The first one is ProvideFault. ProvideFault allows the implementer to receive the response message and change the Message fault as needed. For example, if you got a db exception, like a foreign key error, you wouldn’t want to relay that message back to the client. Instead you might want to replace the message with a more friend message, like database is not operational, or please try again. The second method is HandleError. HandleError receives the exception that has occurred. This is usually where you log the exception and notify you systems administrator of the error.
public class SoapErrorHandler : IErrorHandler { public bool HandleError(Exception error) { return true; } public void ProvideFault(Exception error, MessageVersion version, ref Message fault) { } }
Hooking up your services to use the IErrorHandler
There are several ways to inject an IErrorHandler into your services. I’m going to show you how to do it via your ServiceHost implementation. Another way you can do it is via a service attribute, but I believe that creating a ServiceHost implementation is a more powerful way to control your services and inject behaviors. It will come in handy later down the line if you want to do more sophisticated things. So, this is a good practice worth following.
Below is a definition for our custom IServiceBehavior. Service Behaviors can be used to inject behaviors into your service programmatically. Here we are injecting our custom error handler class into the service. We implemented the ApplyDispatchBehavior, where we can get access to the ChannelDispatcher. The ChannelDispatcher is where we can then add our custom error handler to the collection of error handlers.
public class ErrorHandlerServiceBehavior : IServiceBehavior { private IErrorHandler errorHandler = null; public ErrorHandlerServiceBehavior(IErrorHandler errorHandler) { this.errorHandler = errorHandler; } public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers) { ChannelDispatcher cd = cdb as ChannelDispatcher; if (cd != null) { cd.ErrorHandlers.Add(new SoapErrorHandler()); } } } public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { } public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } }
Below are two class definitions for WadoLabsServiceHostFactory and WadoLabsServiceHost. WadoLabsServiceHostFactory inherits from ServiceHostFactory. This service host factory is used to create new instances of our custom servicehost. WadoLabsServiceHost is our custom servicehost. As you can see our service host overrides the OnOpening() method. There you can get access to Description.Behaviors. Behaviors is a collection of behaviors and is the collection we can add our custom ErrorHandlerBehavior too.
public class WadoLabsServiceHostFactory : ServiceHostFactory { protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) { var serviceHost = new WadoLabsServiceHost(serviceType, baseAddresses); return serviceHost; } } public class WadoLabsServiceHost : ServiceHost { private Type serviceType = null; public WadoLabsServiceHost() : base() { } public WadoLabsServiceHost(Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses) { this.serviceType = serviceType; } protected override void OnOpening() { this.Description.Behaviors.Add(new DefaultErrorHandler()); base.OnOpening(); } protected override void ApplyConfiguration() { base.ApplyConfiguration(); } }
Custom fault messages for SOAP Services
So creating custom fault messages for a SOAP service very simple. Below is an example of a ProvidedFault() implementation where we create a new FaultException of type GreetingFault. GreetingFault is a friendly fault class. We then use the newly create fault exception to crate a new message from the original message.
public void ProvideFault(Exception error, MessageVersion ver, ref Message msg) { FaultException<GreetingFault> fe = new FaultException<GreetingFault>(new GreetingFault(error.Message)); MessageFault fault = fe.CreateMessageFault(); msg = Message.CreateMessage(ver, fault, "http://www.wadolabs.com/ISampleService/SampleMethodGreetingFaultFault"); }
Custom fault messages for RESTful Services
Create custom fault message for REST Services is somewhat similar with a few additions. Below is the an implementation for a WebHttpServiceBehavior class. Instead of inheriting the standard IServiceBehavior interface, we inherit the WebHttpBehavior class instead. We then override the AddServiceHandlers and inject our custom WebHttpServiceErrorHandler here.
public class WebHttpServiceBehavior : WebHttpBehavior { protected override void AddServerErrorHandlers(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher) { endpointDispatcher.ChannelDispatcher.ErrorHandlers.Clear(); endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(new WebHttpServiceErrorHandler()); } }
The implementation of the ProvideFault method demonstrates how to create custom fault message for REST services. In this example, lets assume this service is configured to return json formatted responses. The implementation is very straigt forward. First we have to create a new fault exception of any type. Then using some reflection, we generate a new detail from the newly created fault exception. We then have to create a new message fault by using the generated detail, and a DataContractJsonSerializer. This ensures that the class is serialized into the json format. One last thing that we need to do its specify the message properties. The properties are very important. It defines the content type, as well as the http response code. In this example we are using “application/json” as our content type and returning all exceptions as HttpStatusCode.InternalServerError.
public void ProvideFault(Exception error, MessageVersion version, ref Message fault) { FaultException<Fault> faultException = new FaultException<Fault>(new Fault() { Message = error.Message }); var detail = faultException.GetType().GetProperty("Detail").GetGetMethod().Invoke(faultException, null); fault = Message.CreateMessage(version, "", detail, new DataContractJsonSerializer(detail.GetType())); var webBodyFormatMessageProp = new WebBodyFormatMessageProperty(WebContentFormat.Json); fault.Properties.Add(WebBodyFormatMessageProperty.Name, webBodyFormatMessageProp); var httpResponseMessageProp = new HttpResponseMessageProperty(); httpResponseMessageProp.Headers[HttpResponseHeader.ContentType] = "application/json"; httpResponseMessageProp.StatusCode = HttpStatusCode.InternalServerError; httpResponseMessageProp.StatusDescription = error.Message; fault.Properties.Add(HttpResponseMessageProperty.Name, httpResponseMessageProp); }
Conclusion
There you have it! With windows communication foundation and a few lines of code, you can programmatically shelled all your exceptions from the outside world. This is very important when you are creating a public api and defining you service boundaries. You need to always think about how much information you want to expose to the real world and try your best to hide your implementation details.
1 Response to WCF Exception Handling with IErrorHandler
Matt Weber
July 16th, 2009 at 3:40 am
I used this code to implement IErrorHandler. I can see how you can add “ErrorHandlerServiceBehavior” as a behavior because it inherits “IServiceBehavior”. However, it did not work with my REST service. Not sure why… the code was triggered… it just did not format the exception. I think I need to use “WebHttpBehavior” instead.
Can you please clarify how you can add the behavior”WebHttpServiceBehavior”. When I try to add it I get an error because it is not “IServiceBehavior”.
I am trying to use something like this:
MyServiceHost.Description.Behaviors.Add(New MyBehaviorExtention())