25

I have a C# console application project using .NET 4.0, with the Microsoft.Bcl.Async package installed. I use this code:

internal class Program
{
    private static void Main(string[] args)
    {
        Foo().Wait();
    }

    static void Log(Exception ex)
    {

    }

    private static async Task Foo()
    {
        try
        {
            await DoSomething();
        }
        catch (Exception ex)
        {
            Log(ex);
        }
    }

    private static async Task DoSomething()
    {
        throw new DivideByZeroException();
    }
}

If I put a breakpoint inside of the Log method, I get my DivideByZero exception, but the stack trace I see is:

at Microsoft.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Microsoft.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccess(Task task)
at Microsoft.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
at Microsoft.Runtime.CompilerServices.TaskAwaiter.GetResult()
at AsyncStacks.Program.<Foo>d__0.MoveNext() in p:\Sandbox\AsyncStacks\AsyncStacks\Program.cs:line 25

This stack trace is next to useless as it doesn't tell me where the exception was actually thrown.

If I change my project to target .NET 4.5, I get a more useful exception:

at AsyncStacks.Program.<DoSomething>d__3.MoveNext() in p:\Sandbox\AsyncStacks\AsyncStacks\Program.cs:line 35
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at AsyncStacks.Program.<Foo>d__0.MoveNext() in p:\Sandbox\AsyncStacks\AsyncStacks\Program.cs:line 25

How can I get a useful stack trace from a .NET 4.0 project when using await?

Update

The "old" AsyncTargetingPack does throw a much better stack trace. The issue seems to have been introduced in the "new" Microsoft.Bcl.Async.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Paul Stovell
  • 32,377
  • 16
  • 80
  • 108
  • Possible duplicate of [Is it possible to get a good stack trace with .NET async methods?](http://stackoverflow.com/questions/15410661/is-it-possible-to-get-a-good-stack-trace-with-net-async-methods) – mnemonic Aug 05 '16 at 12:41

1 Answers1

7

Changing Foo to this appears to get a better result:

private static async Task Foo()
{
    await DoSomething().ContinueWith(t => Log(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
}

Update: However, the downside is you have to use the same .ContinueWith every time you use the await keyword. I.e., if you await something that also awaits, you need to .ContinueWith that too.

Paul Stovell
  • 32,377
  • 16
  • 80
  • 108
  • 2
    +1 for both question and answer - however, I think your meant `Log(t.Exception.InnerException)` – YK1 Jul 29 '13 at 15:29