WCF Global Exception Handling






4.82/5 (15 votes)
WCF Global Exception Handling
In WCF, all unhandled exceptions can be handled globally to avoid the service client going in to fault state.
- Implement
IErrorHandler
as follows:using System; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Dispatcher; namespace WcfService1 { public class GlobalErrorHandler : IErrorHandler { /// <summary> /// The method that's get invoked if any unhandled exception raised in service /// Here you can do what ever logic you would like to. /// For example logging the exception details /// Here the return value indicates that the exception was handled or not /// Return true to stop exception propagation and system considers /// that the exception was handled properly /// else return false to abort the session /// </summary> /// <param name="error"></param> /// <returns></returns> public bool HandleError(Exception error) { return true; } /// <summary> /// If you want to communicate the exception details to the service client /// as proper fault message /// here is the place to do it /// If we want to suppress the communication about the exception, /// set fault to null /// </summary> /// <param name="error"></param> /// <param name="version"></param> /// <param name="fault"></param> public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault) { var newEx = new FaultException( string.Format("Exception caught at Service Application GlobalErrorHandler{0}Method: {1}{2}Message:{3}", Environment.NewLine, error.TargetSite.Name, Environment.NewLine, error.Message)); MessageFault msgFault = newEx.CreateMessageFault(); fault = Message.CreateMessage(version, msgFault, newEx.Action); } } }
- Then implement
IServiceBehavior
and extendAttribute
class as follows:using System; using System.Collections.ObjectModel; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Description; using System.ServiceModel.Dispatcher; namespace WcfService1 { public class GlobalErrorBehaviorAttribute : Attribute, IServiceBehavior { private readonly Type errorHandlerType; /// <summary> /// Dependency injection to dynamically inject error handler /// if we have multiple global error handlers /// </summary> /// <param name="errorHandlerType"></param> public GlobalErrorBehaviorAttribute(Type errorHandlerType) { this.errorHandlerType = errorHandlerType; } #region IServiceBehavior Members void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase) { } void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters) { } /// <summary> /// Registering the instance of global error handler in /// dispatch behavior of the service /// </summary> /// <param name="description"></param> /// <param name="serviceHostBase"></param> void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase) { IErrorHandler errorHandler; try { errorHandler = (IErrorHandler)Activator.CreateInstance(errorHandlerType); } catch (MissingMethodException e) { throw new ArgumentException("The errorHandlerType specified in the ErrorBehaviorAttribute constructor must have a public empty constructor.", e); } catch (InvalidCastException e) { throw new ArgumentException("The errorHandlerType specified in the ErrorBehaviorAttribute constructor must implement System.ServiceModel.Dispatcher.IErrorHandler.", e); } foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers) { ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher; channelDispatcher.ErrorHandlers.Add(errorHandler); } } #endregion IServiceBehavior Members } }
Now you are almost done. You just need to decorate your service class as follows:
using System;
namespace WcfService1
{
[GlobalErrorBehaviorAttribute(typeof(GlobalErrorHandler))]
public class Service1 : IService1
{
public string GetData(int value)
{
throw new NotImplementedException();
//return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
}
Please note:
It is good practice to handle the exceptions at the methods that raises the exception. But sometimes, we may need a global solution for handling un-handled exceptions to avoid client objects going into fault state.