Catching Exceptions with Elmah within WCF

We all use the excellent ELMAH to deal with unhandled exceptions in an ASP.NET 3.5 web or MVC application. This works extremely well for all of the site, now what about WCF how can we get Elmah to work for us?

You can use the HttpHandler, and Decorate your Service(s) with an Error Handling attribute.

The ServiceErrorBehaviourAttribute:

using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

/// <summary>
/// So we can decorate Services with the [ServiceErrorBehaviour(typeof(HttpErrorHandler))]
/// ...and errors reported to ELMAH
/// </summary>
public class ServiceErrorBehaviourAttribute : Attribute, IServiceBehavior
{
    readonly Type _errorHandlerType;

    public ServiceErrorBehaviourAttribute(Type errorHandlerType)
    {
        this._errorHandlerType = errorHandlerType;
    }

    public void Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
    {
    }

    public void AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
    {
        var errorHandler = (IErrorHandler)Activator.CreateInstance(_errorHandlerType);
        foreach (var channelDispatcher in serviceHostBase.ChannelDispatchers.OfType<ChannelDispatcher>())
        {
            channelDispatcher.ErrorHandlers.Add(errorHandler);
        }
    }
}

Now the HttpErrorHandler:

using Elmah;
using System;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;

/// <summary>
/// Your handler to actually tell ELMAH about the problem.
/// </summary>
public class HttpErrorHandler : IErrorHandler
{
    public bool HandleError(Exception error)
    {
        return false;
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        if (error == null) return;

        ErrorLog.GetDefault(null).Log(new Error(error));
    }
}

Now it is just a simple case of adding an attribute to the WCF Service:

[ServiceErrorBehaviour(typeof(HttpErrorHandler))]
public class Game : IGame
{

Here is a small sample application showing it in action

WcfService1.zip (8.26 kb)

Overloading Methods in WCF

Is this possible?

It is possible to overload a method in WCF.  However, when you want to expose overloaded methods as operations in a WCF contract, there is more to it than simply writing two or more methods with the same name.

Consider the following example:

[ServiceContract]
public interface ICalendarService
{
   [OperationContract]
   ScheduledEvent[] GetScheduledEvents(DateTime date);

   [OperationContract]
   ScheduledEvent[] GetScheduledEvents(DateTime start, DateTime end);
}

Now, try to actually implement this interface and host it as a WCF service.  An InvalidOperationException will be raised when you invoke ServiceHost.Open. 

As far as the C# compiler is concerned, this is a completely legal piece of code.  The interface contains two methods.  The methods have the same name, but their signatures are unique since their parameters differ.  The interface and methods are decorated with attributes.  However, WCF doesn’t have any special hooks into the compiler. Consequently, the compiler doesn’t have any special knowledge about the attributes.  It is simply going to emit their information in the assembly metadata.

When WCF attempts to start the service, it essentially interrogates the metadata to generate a WSDL contract.  WSDL is all about technology neutral, message based communication.  It doesn’t support object-oriented concepts such as inheritance and overloading.  (Actually, I think the earliest versions of WSDL allowed overloading to a certain extent, but it has since been removed in the newer versions.)  So, WCF basically detects there are two methods with the same name and raises an exception to indicate this isn’t allowed even though the code compiled without any errors.

Regardless, WCF still provides the ability to overload methods.  This can be achieved by using the name property of the OperationContract attribute.  By default, the name of the method will be used for the value of the name property.  However, you can explicitly set the value of the name property to provide a unique value.  Under the covers, WCF will use the value you supply as the name of the corresponding operation in the generated WSDL.

Here is our previous example revised to use alias method names:

[ServiceContract]
public interface ICalendarService
{
   [OperationContract(Name = "GetScheduledEventsByDate")]
   ScheduledEvent[] GetScheduledEvents(DateTime date);

   [OperationContract(Name = "GetScheduledEventsByDateRange")]
   ScheduledEvent[] GetScheduledEvents(DateTime start, DateTime end);
}

You may be wondering how the method will appear to the consumer of the service.  Will it appear as two different names (based on the the alias) or as overloaded methods with the same name?  This will depend upon the proxy class used by your client.  If you use the proxy class that is automatically generated by svcutility.exe, the alias method names will be used.  However, you can manually edit the generated proxy class to achieve the appearance of overloaded methods on the client as well.  This can be accomplished by applying the same attributes to the methods defined in the interface that is used by the proxy class.

Original article from Jeff Barnes