stackMeUp
stackMeUp

Reputation: 171

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?

Upvotes: 1

Views: 348

Answers (1)

Timothy Stepanski
Timothy Stepanski

Reputation: 1196

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();
    }
}

Upvotes: 2

Related Questions