Paul Michaels
Paul Michaels

Reputation: 16695

Error handling using delegates

I have a common method that I'm using to handle a specific error that may come back from a number of functions:

protected async Task<T> RunMyMethod<T>(Func<T> method)
{
    try
    {
        var returnValue = await Task.Run<T>(method);
        return returnValue;
    }
    catch (MyCustomException)
    {
        // Force a clean shutdown of the software 
        ShutdownApplication();
        return default(T);
    }
}

Here's an example of how that is then used in a derived class:

private async Task<IEnumerable<MyData>> GetMyData()
{
    var returnValue = await base.RunMyMethod<IEnumerable<MyData>>(() =>
    {
        var returnval = GetMyDataFromServer();
        return returnval;
    });

    return returnValue;
}

When an exception of type MyCustomException occurs in GetMyDataFromServer() the software doesn't drop into the catch block. I get the following error in the function GetMyData():

An exception of type 'System.ServiceModel.FaultException`1' occurred in mscorlib.dll but was not handled in user code

Additional information: Exception of type 'MyCustomException' was thrown.

This is with only User-unhandled exceptions turned on.

GetMyDataFromServer() communicates with a WCF service. This service is what throws the error.

ChannelFactory<TChannel> cf = new ChannelFactory<TChannel>(endPointName);
Binding binding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);                    

var clientCredentials = new ClientCredentials();

. . .

channel = cf.CreateChannel();
var data = channel.CallWCFService();

Having looked around on-line, it appeared that the correct way to handle this was to change the base method as follows:

protected async Task<T> RunMyMethod<T>(Func<T> method)
{
    var returnValue = await Task.Run<T>(method).ContinueWith(e => 
    {                     
        ShutdownApplication();
        return default(T);
    }, TaskContinuationOptions.OnlyOnFaulted);

    return returnValue;
}

When I run this, I'm obviously not trapping for the correct error message, but I'm just getting a TaskCancellationException.

So, I have two questions: is my conclusion about how to handle this exception correct and, if so, how do I trap a specific error; and why am I getting a TaskCancellationException?

Upvotes: 0

Views: 1098

Answers (1)

i3arnon
i3arnon

Reputation: 116558

You get TaskCancellationException because the continuation is cancelled as it's conditional (i.e. TaskContinuationOptions.OnlyOnFaulted) and the condition isn't met since the antecedent task wasn't faulted.

There's no reason to use that method of adding a continuation. Using async-await like you did at the start is good enough (and even simpler).

The issue is that you are trying to catch MyCustomException but that isn't the exception being thrown. Since you're using WCF the exception is FaultException. You can check the "real" exception stored in FaultException.InnerException.

Upvotes: 1

Related Questions