Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

WCF Global Exception Handling

4.82/5 (15 votes)
22 Apr 2015CPOL 37.9K  
WCF Global Exception Handling

In WCF, all unhandled exceptions can be handled globally to avoid the service client going in to fault state.

  1. Implement IErrorHandler as follows:
    C#
    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);
            }
        }
    }
  2. Then implement IServiceBehavior and extend Attribute class as follows:
    C#
    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:

C#
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)