Search code examples
c#wcferror-handlingserviceproxy

Handling errors within a proxy - WCF


A good suggestion on how to handle errors within a Client can be found here.
Copying here for easy access:

MyServiceClient myServiceClient = new MyServiceClient();

try
{
    documents = myServiceClient.GetDocuments();
    // More code that isn't useful including here ...
    myServiceClient.Close();
}
catch (TimeoutException exception)
{
    MessageBox.Show(exception.Message, "Timeout error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    myServiceClient.Abort();
}
catch (FaultException<ServiceErrorDetails> error)
{
    MessageBox.Show(error.Detail.Message, "Service error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    myServiceClient.Abort();
}
catch (CommunicationException exception)
{
    MessageBox.Show(exception.Message, "Communication error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    myServiceClient.Abort();
}

Now the problem I am having with this solution is that my Proxy contains many many methods. Easy to understand I would rather not want to add this huge try/catch statement around all my method calls.
Instead, I thought it could be a good idea to add the error handling from within MyServiceClient() class.
But the question is how to do that without polluting all the Methods here again with this try/catch statement?
How would you approach that?


Solution

  • You could try encapsulating the try/catch logic in a handler class as follows:

    public static class Example
    {
        public static void ExecuteExample()
        {
            var serviceClient = new ServiceClient();
    
            var documents = ProxyErrorHandler.Execute(serviceClient, serviceClient.GetDocuments);
        }
    }
    
    public static class ProxyErrorHandler
    {
        public static void Execute(ServiceClient serviceClient, Action actionToExecute)
        {
            Execute(serviceClient, () =>
            {
                actionToExecute();
    
                return true;
            });
        }
    
        public static T Execute<T>(ServiceClient serviceClient, Func<T> functionToExecute)
        {
            try
            {
                return functionToExecute();
            }
            catch (Exception exception)
            {
                ShowException(serviceClient, exception);
    
                return default;
            }
        }
    
        public static Task ExecuteAsync(ServiceClient serviceClient, Func<Task> actionToExecute)
        {
            return ExecuteAsync(serviceClient, async () =>
            {
                await actionToExecute();
    
                return true;
            });
        }
    
        public static async Task<T> ExecuteAsync<T>(ServiceClient serviceClient, Func<Task<T>> functionToExecute)
        {
            try
            {
                return await functionToExecute();
            }
            catch (Exception exception)
            {
                ShowException(serviceClient, exception);
    
                return default;
            }
        }
    
        private static void ShowException(ServiceClient serviceClient, Exception exception)
        {
            string title;
            var message = exception.Message;
    
            switch (exception)
            {
                case TimeoutException:
                    title = @"Timeout error";
                    break;
                case FaultException<ServiceErrorDetails> faultException:
                    title = @"Service error";
                    message = faultException.Detail.Message;
                    break;
                case CommunicationException:
                    title = @"Communication error";
                    break;
                default:
                    ExceptionDispatchInfo.Throw(exception);
                    
                    // Unreachable
                    throw new Exception();
            }
    
            MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Error);
    
            serviceClient.Abort();
        }
    }