Search code examples
c#.netasync-awaitsilverlight-5.0stack-trace

Stack trace not providing exception source method when using async in Silverlight 5


I create a new Silverlight 5 project in VS2013 and add the Microsoft Async (1.0.168) NuGet package. I then create a simple async event handler as follows:

private async void OnButtonClick(object sender, RoutedEventArgs e)
{
    await AsyncMethod();
}

private static async Task AsyncMethod()
{
    await TaskEx.Run(() => { });
    NormalMethod();
}

private static void NormalMethod()
{
    throw new Exception("test exception");
}

When I click the button I get the following exception:

{System.Exception: test exception
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 SilverlightApplication1.MainPage.<OnButtonClick>d__0.MoveNext()}

The key piece of information missing here that I want for debug purposes is the source method of the exception (i.e. NormalMethod).

I've reviewed some related questions (linked below) and think I understand the effect async has on stack traces, but I don't understand why the framework wouldn't throw the exception in such a way as to maintain knowledge of the source method. Any ideas/suggestions on how to simply get this information?

Related questions:
Missing exception stack trace informations when using Async Targeting Pack in Silverlight 5.0
Is it possible to get a good stack trace with .NET async methods?


Solution

  • Try this gist of mine:

    https://gist.github.com/aelij/7d37fa3657921cbd9d3d

    The difference between the above code and the official Microsoft.Bcl.Async implementation is the method PrepareExceptionForRethrow. Silverlight doesn't have ExceptionDispatchInfo, so the original implementation rethrows the exception, thus losing the original stack trace information. This code attempts to wrap the exception as an inner exception of the same type, by searching for a suitable constructor.