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
{
public bool HandleError(Exception error)
{
return true;
}
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 extend Attribute
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;
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)
{
}
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();
}
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.
CodeProject