WCF & Exception Handling Improvements for V2.0

Coordinator
Jul 8 2011 at 4:27 PM

We received feedback regarding our initial V1.0 exception handling implementation where there was some code that was a bit redundant and could be consolidated in a single place.

Our current approach in V2.0 has all the Exception Handling located in a single point, a WCF behavior attibute which calls to an Error-Handler.

Therefore, our WCF Service looks like the following:

    [ApplicationErrorHandlerAttribute()] // manage all unhandled exceptions
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    [UnityInstanceProviderServiceBehavior()] //Instances injection behavior
    public class ERPModuleService : IERPModuleService
    {
        ICustomerAppService _customerAppService;
        ISalesAppService _salesAppService;

        public ERPModuleService(ICustomerAppService customerAppService,

                               ISalesAppService salesAppService)
        {
            if (customerAppService == null)
                throw new ArgumentNullException("customerAppService");

            if (salesAppService == null)
                throw new ArgumentNullException("salesAppService");

            _customerAppService = customerAppService;
            _salesAppService = salesAppService;
        }
        
        public CustomerDTO AddNewCustomer(CustomerDTO customer)
        {

            //A single line of code publishing ‘Application Services Façade’
            return _customerAppService.AddNewCustomer(customer);
        }


       //OTHER WCF methods

       //...
    }

Then, you can see that we are implementing the [ApplicationErrorHandlerAttribute()] in order to handle the exceptions.

This is the implementation of that attribute:

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
    public sealed class ApplicationErrorHandlerAttribute
                           : AttributeIServiceBehavior
    {
        

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, 

                                         System.ServiceModel.ServiceHostBase serviceHostBase)
        {
            if (serviceHostBase != null
                &&
                serviceHostBase.ChannelDispatchers.Any())
            {
                //add default error handler for all dispatchers in wcf services
                foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
                    dispatcher.ErrorHandlers.Add(new ApplicationErrorHandler());
            }
        }
        // OTHER METHODS OMMITTED
        }

    }

 

Then, we are using the ApplicationErrorHandler class (IErrorHandler):

public sealed class ApplicationErrorHandler
                                 : IErrorHandler
    {
        public bool HandleError(Exception error)
        {
            if (error != null)
                LoggerFactory.CreateLog().LogError(Messages.error_unmanagederror, error);

            //set  error as handled 
            return true;
        }

        public void ProvideFault(Exception error, 

                                 System.ServiceModel.Channels.MessageVersion version, 

                                 ref System.ServiceModel.Channels.Message fault)
        {
            if (error is FaultException<ApplicationServiceError>)
            {
                MessageFault messageFault = ((FaultException<ApplicationServiceError>)error).

                                                                         CreateMessageFault();

                //propagate FaultException
                fault = Message.CreateMessage(version, messageFault, (

                                       (FaultException<ApplicationServiceError>)error).Action

                                                                    );
            }
            else
            {
                //create service error
                ApplicationServiceError defaultError = new ApplicationServiceError()
                {
                    ErrorMessage = Resources.Messages.message_DefaultErrorMessage
                };

                //Create fault exception and message fault
                FaultException<ApplicationServiceError> defaultFaultException = 

                                     new FaultException<ApplicationServiceError>(defaultError);
                

               MessageFault defaultMessageFault = defaultFaultException.CreateMessageFault();

                //propagate FaultException
                fault = Message.CreateMessage(version, defaultMessageFault, 

                                             defaultFaultException.Action);
            }
        }
    }

 

Any feedback about this new implementation that we made for V2.0?.

We’d really appreciate any constructive feedback about it.

Thanks a lot!, :-)

Cesar.

Jul 21 2011 at 3:46 AM

Maybe you could use the EntLib - Exception Handling App Block - ExceptionShieldingAttribute?

Coordinator
Jul 21 2011 at 4:57 AM

I agree, in fact, in the Guide eBook we suggest that option (P&P EntLib - ExceptionShieldingAttribute).

We are not using it in the SampleApp because we don't want to include many external dependencies.

Thanks! :-)