Async/await exception and Visual Studio 2013 debug output behavior

I'm developing an application in C# that communicates with Dynamics NAV through web services. To reduce duplicate code and because there will be many endpoints, I have created a generic async/await method that executes the service calls and handle exceptions.

The method works but I'm seeing an unexpected behavior in the Visual Studio 2013 output window when an exception occur(and is handled).

Test code and output can be seen below.

My concern is the "A first chance exception of type..." lines which I'm seeing 4 times when using the async/await methods. Does this exception really occur 4 times?

When calling the service synchronously there's only one exception line which is expected.

Is this just Visual Studio 2013 or is there something wrong with my async/await code?

Is there maybe a better way of doing what I'm trying to accomplish?

class Program
{
    static void Main(string[] args)
    {
        Debug.WriteLine("Synchronous...");
        try
        {
            TestFunctions_PortClient service = new TestFunctions_PortClient();

            service.Open();

            string result = service.ErrorTest();

            Debug.WriteLine(result);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }

        Debug.WriteLine(string.Empty);
        Debug.WriteLine("Async...");
        NavServiceTest navService = new NavServiceTest();

        navService.TestAsync();

        Console.ReadLine();
    }
}

class NavServiceTest
{
    public async void TestAsync()
    {
        try
        {
            string result = await CallServiceAsync();

            Debug.WriteLine(result);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
    }

    private async Task<string> CallServiceAsync()
    {
        TestFunctions_PortClient service = new TestFunctions_PortClient();

        service.Open();

        ErrorTest_Result result = await ExecuteServiceAsync<ErrorTest_Result>(
            service.InnerChannel,
            service.Endpoint,
            service.ErrorTestAsync());

        return result.return_value;
    }

    private async Task<T> ExecuteServiceAsync<T>(IClientChannel channel, ServiceEndpoint endpoint, Task<T> source)
    {
        var tcs = new TaskCompletionSource<T>();
        Task<T> task = tcs.Task;

        try
        {
            Debug.WriteLine("ExecuteServiceAsync");

            tcs.TrySetResult(await source);
        }
        catch (EndpointNotFoundException ex)
        {
            Debug.WriteLine("EndpointNotFoundException");
            tcs.TrySetException(ex);
        }
        catch (FaultException ex)
        {
            Debug.WriteLine("FaultException");
            tcs.TrySetException(ex);
        }
        catch (Exception ex)
        {
            Debug.WriteLine("Exception");
            tcs.TrySetException(ex);
        }
        finally
        {
            if (channel != null)
            {
                if (channel.State == CommunicationState.Faulted)
                    channel.Abort();
                else
                    channel.Close();
            }
        }

        if (task.IsFaulted)
        {
            throw task.Exception.InnerException;
        }

        return task.Result;
    }
}

Here's the output of the code above.

Synchronous...
A first chance exception of type 'System.ServiceModel.FaultException' occurred in mscorlib.dll
Error from NAV

Async...
ExecuteServiceAsync
A first chance exception of type 'System.ServiceModel.FaultException' occurred in mscorlib.dll
FaultException
A first chance exception of type 'System.ServiceModel.FaultException' occurred in ServiceTest.exe
A first chance exception of type 'System.ServiceModel.FaultException' occurred in mscorlib.dll
A first chance exception of type 'System.ServiceModel.FaultException' occurred in mscorlib.dll
Error from NAV
Jon Skeet
people
quotationmark

When an exception occurs in an async method, it doesn't just propagate up the stack like it does in synchronous code. Heck, the logical stack is likely not to be there any more.

Instead, the exception is stored in the task which represents the asynchronous operation. Then, when you await the asynchronous operation, the GetResult method of the TaskAwaiter will rethrow the original exception. If that isn't caught in your code, then it will be caught by the compiler-generated code again and put into the task that represents that operation, etc. So if you have a chain of asynchronous methods (as is often the case) and the deepest one throws an exception, the exception propagation will actually be a "throw in GetResult, catch, stuff into task" per link in the chain.

So yes, the exception is being thrown four times, in order to effectively only be thrown once. If you're worried about the efficiency of that, I suspect it's not too bad - because the logical stack trace is only determined once. I dare say it's less efficient than the synchronous version, but my general philosophy is that if you're seeing so many exceptions that they're affecting your performance significantly, then either you're overusing exceptions or your system is in a really bad state anyway, and performance is the least of your worries.

people

See more on this question at Stackoverflow