I am sure most of you have used Error Logging Module and Handlers (ELMAH) for ASP.NET. ELMAH is one great open source project and real blessings for ASP.NET developers. If you don’t know about it, It’s a MUST SEE tool and in that case I would recommend you to read out Scott Ha introductory blog post on ELMAH.
BUT, in this post we are going to see how to configure ELMAH to work with WCF services because if you do that in a typical way then ELMAH is probably not going to work as expected and it won’t show you any unhandled exception.
So let’s get started!
I have created a new WCF Application project ElmahWithWcf containing one contract IDemoService and service implementation class DemoService.
To add ELMAH, you can either download it from project host site and configure it or you can simply use NuGet to download and automatically install/configure ELMAH.
NuGet is a Visual Studio extension that makes it easy to install and update open source libraries and tools in Visual Studio. Perhaps it really does simplify the life of developer when it comes to configure third party open source libraries. If you haven’t used NuGet, I would strongly encourage you to install it from Visual Studio Extension Manager (Tools –> Extension Manager). It’s free. You can also read NuGet documentation on CodePlex.com for further help or ping me back.
Once you have installed it, you can Add/Configure ELMAH via “Add Library Package Reference” in context menu of references folder.
In Add Library Package Reference, search elmah in online packages and click install, which will automatically download the required assemblies and configure entries in web.config as well. Isn’t it cool?
Just in case if you don’t believe, with NuGet you get all the config entries automatically!!!
With this ELMAH is now configured as you would typically do in ASP.NET web application, however, in contrast to ASP.NET app, it won’t log any unhandled exception that is raised in WCF service. For this, to work correctly, you need to create custom Error Handler implementing IErrorHandler as demonstrated in code snippet below:
[csharp]
public class ElmahErrorHandler: IErrorHandler
{
#region IErrorHandler Members
public bool HandleError(Exception error)
{
return false;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
if (error == null)
{
return;
}
if (HttpContext.Current == null)
{
return;
}
Elmah.ErrorSignal.FromCurrentContext().Raise(error);
}
#endregion
}
//Further in addition to that, you need to create a Service Behavior Attribute implementing Attribute and IServiceBehavior
public class ServiceErrorBehaviorAttribute: Attribute, IServiceBehavior
{
private readonly Type errorHandlerType;
public ServiceErrorBehaviorAttribute(Type errorHandlerType)
{
this.errorHandlerType = errorHandlerType;
}
#region IServiceBehavior Members
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection < ServiceEndpoint > endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
IErrorHandler errorHandler;
errorHandler = Activator.CreateInstance(errorHandlerType) as IErrorHandler;
if (errorHandler != null)
{
foreach(ChannelDispatcherBase dispatcher in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher cd = dispatcher as ChannelDispatcher;
cd.ErrorHandlers.Add(errorHandler);
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
#endregion
}
//And finally you need to apply the custom attribute on your service implementation class
[ServiceErrorBehavior(typeof(ElmahErrorHandler))]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class DemoService: IDemoService
{
#region IDemoService Members
public string GetData(int value)
{
throw new Exception("TEST");
return string.Format("You entered: {0}", value);
}
#endregion
}
[/csharp]
That is all you need to do for ELMAH to work with WCF.
At this point, ELMAH must show all unhandled exception in log file. For example, line number 9 throws an exception with message “Test”. If we invoke the service method, the ELMAH should log this exception. The log file can be browsed at http://ServerPath/elmah.axd
In fact, ELMAH is so convenient that we decided not to use Enterprise Library Logging Block and utilized ELMAH to log even handled exception as well (Yes another reason was timelines as well).
Did I hear How? Well, in that case you simply need to manually add one line in catch block.
This will inform/raise about the exception to ELMAH and so it will log the handled exception as well.
Hope this Helps!
In case of any feedback/experience, please do share…
Happy Coding!
5 Comments
KevDog · May 11, 2011 at 11:16 am
Excellent post, definitely will be jacking this one in.
Anonymous · June 12, 2011 at 2:12 pm
Nice One Adil
[Kamran Shahid]
wyousuf · October 11, 2011 at 12:50 pm
In my case Elmah.ErrorSignal.FromCurrentContext() was giving me null value. For alternative approach you can use this line of code Elmah.ErrorLog.GetDefault(null).Log(new Elmah.Error(exception));
Waqas Yousuf
Adil Mughal · October 14, 2011 at 3:11 pm
Thanks Waqas for sharing your experience to readers.
Salvadore · May 27, 2014 at 5:58 am
Hi Adil, Thanks for this very useful blog.
BTW just a minor amendements for “Collection endpoints,” in AddBindingParameters method – it must be Collection endpoints,