Error Handling in Wcf with a Custom Behavior March, 2009
Looks like this has been done already in various ways on the web, I'll add mine to the mix. I just wanted a behavior that would allow me to select the error handler for a particular service and would be configurable. So I start off by creating a behavior extension element:
public class ErrorHandlerBehaviorElement : BehaviorExtensionElement { #region BehaviorExtensionElement Overrides public override Type BehaviorType { get { return typeof(ErrorHandlerBehavior); } } protected override object CreateBehavior() { return new ErrorHandlerBehavior(Type.GetType(ErrorHandlerType)); } [ConfigurationProperty("errorHandlerType", IsRequired = true)] public string ErrorHandlerType { get { return (string)base["errorHandlerType"]; } set { base["errorHandlerType"] = value; } } #endregion }
This is really just a ConfigurationElement so you would add additional configuration as you normally would. I'm using the declarative approach above. Next, define the behavior:
public class ErrorHandlerBehavior : IServiceBehavior { #region Private Fields private Type _type; #endregion #region Constructor public ErrorHandlerBehavior(Type type) { _type = type; } #endregion #region IServiceBehavior Members public void ApplyDispatchBehavior( ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase) { IErrorHandler errorHandler = (IErrorHandler)Activator.CreateInstance(_type); foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers) { dispatcher.ErrorHandlers.Add(errorHandler); } } public void AddBindingParameters( ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) { } public void Validate( ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase) { } #endregion }
In the ApplyDispatchBehavior method I create the error handler and add it to all the channel dispatchers in the service. The error handler itself is very simple; simply hides/logs any exceptions that are not FaultExceptions.
public class UnhandledFaultException : FaultException { public UnhandledFaultException() : base("An unexpected error has occured. Please contact technical support for assistance.") { } }
public class ErrorHandler : IErrorHandler { #region IErrorHandler Members public void ProvideFault( Exception error, MessageVersion version, ref Message fault) { if (!(error is FaultException)) { FaultException exception = new UnhandledFaultException(); MessageFault messageFault = exception.CreateMessageFault(); fault = Message.CreateMessage(version, messageFault, exception.Action); } } public bool HandleError(Exception error) { if (!(error is FaultException)) { // TODO: Log errors here } return false; } #endregion }
Next, I need to add the behavior to my configuration. The Wcf Configuration Editor actually handled this very nicely. I was able to do it all visually. Here is the actual configuration:
<system.serviceModel> <extensions> <behaviorExtensions> <add name="errorHandler" type="MyLib.ErrorHandlerBehaviorElement, MyLib" /> behaviorExtensions> extensions>
<services> <service behaviorConfiguration="MyServiceBehavior" name="MyService">...service> services>
<behaviors> <serviceBehaviors> <behavior name="MyServiceBehavior">
... <errorHandler errorHandlerType="MyLib.ErrorHandler, MyLib" /> behavior> serviceBehaviors> behaviors> system.serviceModel>
Further reading:
1) Programming WCF Services - Juval Lowy, Page 221 in 1st Edition