Daily Knowledge Drop
When multiple async method are called in a sequence, the async methods should be elided
and the Tasks should be awaited and not passed up the call stack.
If a Task is passed up the stack, and an exception occurs - the Task which is not awaited will not be part of the error stack trace.
No await exception
In the below code snippet, we have a call stack where a Task is not awaited immediately
, but passed up the call stack to be awaited:
await CallStackStart();
static async Task CallStackStart()
{
try
{
// call a method which returns a task
await NoAwaitMethod();
}
catch (Exception e)
{
Console.WriteLine("Stacktrace for the exception:");
Console.WriteLine(e);
}
}
// return a Task
static Task NoAwaitMethod()
{
// call a method which returns a Task but
// do NOT await
return ThrowExceptionAsync();
}
static async Task ThrowExceptionAsync()
{
await Task.Delay(1);
throw new Exception("Manual exception has been thrown");
}
Starting from the bottom of the call stack:
ThrowExceptionAsync
is an async method in which an exception could (will in this example) be thrown.NoAwaitMethod
calls into ThrowExceptionAsync, but does not await the call. The method returns the Task returned from ThrowExceptionAsyncCallStackStart
calls into NoAwaitMethod and awaits the Task the method returns - which is the Task returned from ThrowExceptionAsync.
Running the above code, the call stack generated from the exception is:
Stacktrace for the exception:
System.Exception: Manual exception has been thrown
at Program.<<Main>$>g__ThrowExceptionAsync|0_2() in C:\Development\Blog\ElideAwait\Program.cs:line 28
at Program.<Main>$(String[] args) in C:\Development\Blog\ElideAwait\Program.cs:line 5
The stack trace has no mention that the call stack went through the NoAwaitMethod method!
. This is due to the fact that the method is basically just a pass through method for the Task.
To get a more accurate stack trace, the async method needs to be awaited.
await exception
As mentioned above, instead of a method like NoAwaitMethod, which serves as a pass through for the Task, the Task should be awaited
:
wait CallStackStart();
static async Task CallStackStart()
{
try
{
// call a method which returns a task
await AwaitMethod();
}
catch (Exception e)
{
Console.WriteLine("Stacktrace for the exception:");
Console.WriteLine(e);
}
}
static async Task AwaitMethod()
{
// await the task returned instead
// of just returning the Task
await ThrowExceptionAsync();
}
static async Task ThrowExceptionAsync()
{
await Task.Delay(1);
throw new Exception("Manual exception has been thrown");
}
Again, starting from the bottom of the call stack:
ThrowExceptionAsync
is an async method in which an exception could (will in this example) be thrown.AwaitMethod
calls into ThrowExceptionAsync, and awaits the call.CallStackStart
calls into NoAwaitMethod and awaits the Task the method returns.
Now running the above code, the full complete stack trace is part of the exception:
Stacktrace for the exception:
System.Exception: Manual exception has been thrown
at Program.<<Main>$>g__ThrowExceptionAsync|0_2() in C:\Development\Blog\ElideAwait\Program.cs:line 28
at Program.<<Main>$>g__AwaitMethod|0_1() in C:\Development\Blog\ElideAwait\Program.cs:line 21
at Program.<Main>$(String[] args) in C:\Development\Blog\ElideAwait\Program.cs:line 6
This time we have a full, complete stack trace!
Notes
When await async is used in conjunction with any exceptions, the Tasks in question should be elided and awaited and not passed up the stack trace as it can cause certain methods to be omitted from exception stack traces.
References
Elide await keyword - Exceptions
Daily Drop 238: 19-01-2023
At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.
The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.On This Page