Stack traces with async/await

C#LoggingStack TraceAsync AwaitVisual Studio-Debugging

C# Problem Overview


It's clear why stack traces are affected with Microsoft's new programming paradigm. We now have a semantic stack and a couple of physical ones (my choice of words).

What I get to see is an exception's StackTrace property (and in the debugger) is the physical ones, concatenated:

private async Task CheckFooAndBar()
{
    var log = LogManager.GetLogger("Test");
    log.Info("CheckFooAndBar");
    try
    {
        await Foo();
    }
    catch (Exception ex)
    {
        log.Info("StackTrace of last exception: " + ex.StackTrace);
    }
    Console.ReadKey();
}
private async Task Foo()
{
    await Task.Factory.StartNew(() => Thread.Sleep(1000));
    await Bar();
    await Task.Factory.StartNew(() => Thread.Sleep(1000));
}
private async Task Bar()
{
    await Task.Factory.StartNew(() => Thread.Sleep(1000));
    throw new Exception();
    await Task.Factory.StartNew(() => Thread.Sleep(1000));
}

This gives:

StackTrace of last exception:    at NLogAsyncExceptionTestCase.Program.<Bar>d__d.MoveNext() in c:\Users\Jens\Documents\Visual Studio 2012\Projects\NLogAsyncExceptionTestCase\NLogAsyncExceptionTestCase.Console\Program.cs:line 53
--- 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 System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at NLogAsyncExceptionTestCase.Program.<Foo>d__8.MoveNext() in c:\Users\Jens\Documents\Visual Studio 2012\Projects\NLogAsyncExceptionTestCase\NLogAsyncExceptionTestCase.Console\Program.cs:line 44
--- 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 System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at NLogAsyncExceptionTestCase.Program.<CheckFooAndBar>d__0.MoveNext() in c:\Users\Jens\Documents\Visual Studio 2012\Projects\NLogAsyncExceptionTestCase\NLogAsyncExceptionTestCase.Console\Program.cs:line 30 

My question is: Is there a (convenient, standard) way to convert this to a proper backtrace in the semantic sense, such as:

CheckFooAndBar
Foo
Bar

Of course there could be a mixture of awaits and inline path fragments in the stack.

I tried looking at the stack as it is with .NET 4.5 and SL5 with the async targetting pack, but not yet with WinRT. The output is from .NET 4.5.

In SL5, which is what I mainly do, the situation is more problematic: You don't get line numbers in stack traces in Silverlight (even with elevated privileges), which makes the need for context more important.

C# Solutions


Solution 1 - C#

With Visual Studio 2013 and .NET 4.5.1, this problem appears to be addressed - and not only in .NET.

Further Reading: Debugging Asynchronous Code in Visual Studio 2013 - Call Stack enhancements.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJohnView Question on Stackoverflow
Solution 1 - C#JohnView Answer on Stackoverflow