Extending Control Over Error Handling and Reporting

Download sample

This sample demonstrates how to extend control over error handling and error reporting in a Windows Communication Foundation (WCF) service using the IErrorHandler interface. The sample is based on the Getting Started Sample with some additional code added to the service to handle errors. The client forces several error conditions. The service intercepts the errors and logs them in a file.

Note

The setup procedure and build instructions for this sample are located at the end of this topic.

Services can intercept errors, perform processing, and affect how errors are reported using the IErrorHandler interface. The interface has two methods that can be implemented: ProvideFault and HandleError. The ProvideFault method allows you to add, modify, or suppress a fault message that is generated in response to an exception. The HandleError method allows error processing to take place in the event of an error and controls whether additional error handling can run.

In this sample, the CalculatorErrorHandler type implements the IErrorHandler interface. In the

HandleError method, the CalculatorErrorHandler writes a log of the error to an Error.txt text file in c:\logs. Note that the sample logs the fault and does not suppress it, allowing it to be reported back to the client.

public class CalculatorErrorHandler : IErrorHandler
{
        // Provide a fault. The Message fault parameter can be replaced, or set to
        // null to suppress reporting a fault.

        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
        }

        // HandleError. Log an error, then allow the error to be handled as usual.
        // Return true if the error is considered as already handled

        public bool HandleError(Exception error)
        {
            using (TextWriter tw = File.AppendText(@"c:\logs\error.txt"))
            {
                if (error != null)
                {
                    tw.WriteLine("Exception: " + error.GetType().Name + " - " + error.Message);
                }
                tw.Close();
            }
            return true;
        }
    }

The ErrorBehaviorAttribute exists as a mechanism to register an error handler with a service. This attribute takes a single type parameter. That type should implement the IErrorHandler interface and should have a public, empty constructor. The attribute then instantiates an instance of that error handler type and installs it into the service. It does this by implementing the IServiceBehavior interface and then using the ApplyDispatchBehavior method to add instances of the error handler to the service.

// This attribute can be used to install a custom error handler for a service.
public class ErrorBehaviorAttribute : Attribute, IServiceBehavior
{
    Type errorHandlerType;

    public ErrorBehaviorAttribute(Type errorHandlerType)
    {
        this.errorHandlerType = errorHandlerType;
    }

    void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
    {
    }

    void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.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);
        }                                                
    }
}

The sample implements a calculator service. The client deliberately causes two errors to occur on the service by providing parameters with illegal values. The CalculatorErrorHandler uses the IErrorHandler interface to log the errors to a local file and then allows them to be reported back to the client. The client forces a divide by zero and an argument-out-of-range condition.

try
{
    Console.WriteLine("Forcing an error in Divide");
    // Call the Divide service operation - trigger a divide by 0 error.
    value1 = 22;
    value2 = 0;
    result = proxy.Divide(value1, value2);
    Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);
}
catch (FaultException e)
{
    Console.WriteLine("FaultException: " + e.GetType().Name + " - " + e.Message);
}
catch (Exception e)
{
    Console.WriteLine("Exception: " + e.GetType().Name + " - " + e.Message);
}

When you run the sample, the operation requests and responses are displayed in the client console window. You see the division by zero and the argument-out-of-range conditions being reported as faults. Press ENTER in the client window to shut down the client.

Add(15,3) = 18
Subtract(145,76) = 69
Multiply(9,81) = 729
Forcing an error in Divide
FaultException: FaultException - Invalid Argument: The second argument must not be zero.
Forcing an error in Factorial
FaultException: FaultException - Invalid Argument: The argument must be greater than zero.

Press <ENTER> to terminate client.

The file c:\logs\errors.txt contains the information logged about the errors by the service. Note that for the service to write to the directory you must make sure that the process under which the service is running, (typically ASP.NET or Network Service), has the permission to write to the directory.

Fault: Reason = Invalid Argument: The second argument must not be zero.
Fault: Reason = Invalid Argument: The argument must be greater than zero.

To set up, build, and run the sample

  1. Ensure that you have performed the One-Time Set Up Procedure for the Windows Communication Foundation Samples.

  2. To build the solution, follow the instructions in Building the Windows Communication Foundation Samples.

  3. Ensure you have created the c:\logs directory for the error.txt file. Or modify the file name used in CalculatorErrorHandler.HandleError.

  4. To run the sample in a single- or cross-machine configuration, follow the instructions in Running the Windows Communication Foundation Samples.

© 2007 Microsoft Corporation. All rights reserved.