WCF Error Handling with log4net
In this blog post I will be going through how to do error handing with WCF by using attributes to log your errors.
There are multiple ways to do error handling in WCF as listed by Pedram Rezaei Blog.
The default way that WCF allows errors message to display is by setting IncludeExceptionDetailInFaults Property to true in web.config or on the service attribute but this is only recommended when you need to debug you development code not in your shipped/release code.
In Web.config file
In the web.config file of the WCF service the includeExceptionDetailFaults attribute set it to true. With this action every endpoint associated to WCF service will send managed exception information.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<system.serviceModel> <services> <service name="ZeytinSoft.WCF.OliveService" behaviorConfiguration="OliveDebugServiceConfiguration"> </service> </services> <behaviors> <serviceBehaviors> <behavior name="OliveDebugServiceConfiguration"> <serviceDebug includeExceptionDetailInFaults="true"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> |
In Attribute
Another way is setting the IncludeExceptionDatailInFaults property to true using the ServiceBehaviorAttribute.
1 2 |
[ServiceBehavior(IncludeExceptionDetailInFaults=true)] public class OliveService{ } |
That is fine and dandy but it is definitely not recommended for production server, you don’t want an stack trace to show up when someone is viewing it on the webpage for this service.
The IErrorHandler interface
The basic form of error logging in WCF is to use the IErrorHandler interface, which enables developers to customize the default exception reporting and propagation, and provides for a hook for custom logging.
1 2 3 4 5 |
public interface IErrorHandler { bool HandleError(Exception error); void ProvideFault(Exception error,MessageVersion version,ref Message fault); } |
Another thing to note is we need to implement the IServiceBehavior also since installing our own custom implementation of IErrorHandler requires adding it to the desired dispatcher. Since we need to treat the extensions as custom service behaviors in order for it to work.
1 2 3 4 5 6 7 8 9 10 11 12 |
public interface IServiceBehavior { void AddBindingParameters(ServiceDescription description, ServiceHostBase host, Collection <ServiceEndpoint> endpoints, BindingParameterCollection parameters); void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase host); void Validate(ServiceDescription description,ServiceHostBase host); } |
Rather than just calling Log4Net I create a class called Logger which decouples log4net so that one can use any logging framework by using a dependency injection framework. (Code not listed)
Back to building our own ErrorHandler, ServiceBehavior with Attribute, the code is listed below
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
[AttributeUsage(AttributeTargets.Class)] public class OliveErrorHandlerBehaviorAttribute : Attribute, IServiceBehavior, IErrorHandler { protected Type ServiceType { get; set; } public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { //Dont do anything } public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection <ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { //dont do anything } public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { ServiceType = serviceDescription.ServiceType; foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers) { dispatcher.ErrorHandlers.Add(this); } } public void ProvideFault(Exception error, MessageVersion version, ref Message fault) { fault = null; //Suppress any faults in contract } public bool HandleError(Exception error) { Logger.LogException(error); //Calls log4net under the cover return false; } } |
Now one can just add an attribute to the WCF service code to log our error message to log4net or whatever logging framework that you may be using.
1 2 3 |
[ServiceContract] [OliveErrorHandlerBehavior] public class OliveService{ } |
There is also another way by using the web.config and adding the error logging to all the services listed by Stever B in his blog, but I find that does not give me the flexibility that I wanted, I may want to log some but not others etc.
Hope you enjoy this post.
This article is very helpfull.. Thank for posting such a nice stuff.
Thanks,
Kulwinder
No problem you are welcome.
This looks like a very nice way to do it, good job 🙂
I’m also using log4net (but without a wrapper..), and have a question:
– where do you initialize the logger? And wich Type do you supply?
– If I log inside HandleError, does log4net show the correct type?
One can initialize the logger by an IoC container (StructureMap, Ninject, Windsor, or a ServiceLocator etc etc) or just in code like in your Attribute
private static readonly ILog log = LogManager.GetLogger(
System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
and then if you wish to log it as an error just use
log.Error(“Service failed : ” + ex.Message);
inside your HandleError call, if you wish for it to be debug just call log.debug its up to you.
Ya, that’s great code, copied from msdn, minus the portions which actually do some error detection in the handling code itself.
http://msdn.microsoft.com/en-us/library/ms751439.aspx
Hi! Can you update you code as I’m not able to compile it. The first issue is in the ApplyDispatchBehavior()’s foreach loop: the variable channelDispatcherBase’s type is causing confusion. If I define it as a var, I cannot add ‘this’ to the Error Handlers. If I leave it defined as ChannelDispatcher, there is a warning about a cast. The second issue is in HandleError: Logger.LogException(error); I cannot find the LogException method in log4Net
What happens if you don’t use a var? Does that work?
Also the LogException is just a wrapper I wrote, you can use the Logger.Warn or Logger.Error or Fatal it is up to you on how you wish to log the information 🙂