A good solution for await in try/catch/finally? - c#

I need to call an async method in a catch block before throwing again the exception (with its stack trace) like this :
try
{
// Do something
}
catch
{
// <- Clean things here with async methods
throw;
}
But unfortunately you can't use await in a catch or finally block. I learned it's because the compiler doesn't have any way to go back in a catch block to execute what is after your await instruction or something like that...
I tried to use Task.Wait() to replace await and I got a deadlock. I searched on the Web how I could avoid this and found this site.
Since I can't change the async methods nor do I know if they use ConfigureAwait(false), I created these methods which take a Func<Task> that starts an async method once we are on a different thread (to avoid a deadlock) and waits for its completion:
public static void AwaitTaskSync(Func<Task> action)
{
Task.Run(async () => await action().ConfigureAwait(false)).Wait();
}
public static TResult AwaitTaskSync<TResult>(Func<Task<TResult>> action)
{
return Task.Run(async () => await action().ConfigureAwait(false)).Result;
}
public static void AwaitSync(Func<IAsyncAction> action)
{
AwaitTaskSync(() => action().AsTask());
}
public static TResult AwaitSync<TResult>(Func<IAsyncOperation<TResult>> action)
{
return AwaitTaskSync(() => action().AsTask());
}
So my questions is: Do you think this code is okay?
Of course, if you have some enhancements or know a better approach, I'm listening! :)

You can move the logic outside of the catch block and rethrow the exception after, if needed, by using ExceptionDispatchInfo.
static async Task f()
{
ExceptionDispatchInfo capturedException = null;
try
{
await TaskThatFails();
}
catch (MyException ex)
{
capturedException = ExceptionDispatchInfo.Capture(ex);
}
if (capturedException != null)
{
await ExceptionHandler();
capturedException.Throw();
}
}
This way, when the caller inspects the exception's StackTrace property, it still records where inside TaskThatFails it was thrown.

You should know that since C# 6.0, it's possible to use await in catch and finally blocks, so you could in fact do this:
try
{
// Do something
}
catch (Exception ex)
{
await DoCleanupAsync();
throw;
}
The new C# 6.0 features, including the one I just mentioned are listed here or as a video here.

If you need to use async error handlers, I'd recommend something like this:
Exception exception = null;
try
{
...
}
catch (Exception ex)
{
exception = ex;
}
if (exception != null)
{
...
}
The problem with synchronously blocking on async code (regardless of what thread it's running on) is that you're synchronously blocking. In most scenarios, it's better to use await.
Update: Since you need to rethrow, you can use ExceptionDispatchInfo.

We extracted hvd's great answer to the following reusable utility class in our project:
public static class TryWithAwaitInCatch
{
public static async Task ExecuteAndHandleErrorAsync(Func<Task> actionAsync,
Func<Exception, Task<bool>> errorHandlerAsync)
{
ExceptionDispatchInfo capturedException = null;
try
{
await actionAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
capturedException = ExceptionDispatchInfo.Capture(ex);
}
if (capturedException != null)
{
bool needsThrow = await errorHandlerAsync(capturedException.SourceException).ConfigureAwait(false);
if (needsThrow)
{
capturedException.Throw();
}
}
}
}
One would use it as follows:
public async Task OnDoSomething()
{
await TryWithAwaitInCatch.ExecuteAndHandleErrorAsync(
async () => await DoSomethingAsync(),
async (ex) => { await ShowMessageAsync("Error: " + ex.Message); return false; }
);
}
Feel free to improve the naming, we kept it intentionally verbose. Note that there is no need to capture the context inside the wrapper as it is already captured in the call site, hence ConfigureAwait(false).

Related

HttpClient.SendAsync() Exception [duplicate]

Everywhere I read it says the following code should work, but it doesn't.
public async Task DoSomething(int x)
{
try
{
// Asynchronous implementation.
await Task.Run(() => {
throw new Exception();
x++;
});
}
catch (Exception ex)
{
// Handle exceptions ?
}
}
That said, I'm not catching anything and get an "unhandled exception" originating at the 'throw' line. I'm clueless here.
You have the "Just my code" Option turned on. With this on, it is considering the exception unhandled with respect to "just your code"--because other code is catching the exception and stuffing it inside of a Task, later to be rethrown at the await call and caught by your catch statement.
Without being attached in the debugger, your catch statement will be triggered, and it will run as you expect. Or you can just continue from within the debugger and it will run as expected.
The better thing to do is to just turn off "Just my code". IMO, it causes more confusion than it is worth.
As SLaks said, your code works fine.
I strongly suspect you over-simplified your example, and have an async void in your code.
The following works fine:
private static void Main(string[] args)
{
CallAsync();
Console.Read();
}
public static async void CallAsync()
{
try
{
await DoSomething();
}
catch (Exception)
{
// Handle exceptions ?
Console.WriteLine("In the catch");
}
}
public static Task DoSomething()
{
return Task.Run(() =>
{
throw new Exception();
});
}
The following doesn't work:
private static void Main(string[] args)
{
CallAsync();
Console.Read();
}
public static void CallAsync()
{
try
{
DoSomething();
}
catch (Exception)
{
// Handle exceptions ?
Console.WriteLine("In the catch");
}
}
public static async void DoSomething()
{
await Task.Run(() =>
{
throw new Exception();
});
}
See http://msdn.microsoft.com/en-us/magazine/jj991977.aspx
Async void methods have different error-handling semantics. When an
exception is thrown out of an async Task or async Task method, that
exception is captured and placed on the Task object. With async void
methods, there is no Task object, so any exceptions thrown out of an
async void method will be raised directly on the
SynchronizationContext that was active when the async void method
started. Figure 2 illustrates that exceptions thrown from async void
methods can’t be caught naturally.
Your code won't even compile cleanly at the moment, as the x++; statement is unreachable. Always pay attention to warnings.
However, after fixing that, it works fine:
using System;
using System.Threading.Tasks;
class Test
{
static void Main(string[] args)
{
DoSomething(10).Wait();
}
public static async Task DoSomething(int x)
{
try
{
// Asynchronous implementation.
await Task.Run(() => {
throw new Exception("Bang!");
});
}
catch (Exception ex)
{
Console.WriteLine("I caught an exception! {0}", ex.Message);
}
}
}
Output:
I caught an exception! Bang!
(Note that if you try the above code in a WinForms app, you'll have a deadlock because you'd be waiting on a task which needed to get back to the UI thread. We're okay in a console app as the task will resume on a threadpool thread.)
I suspect the problem is actually just a matter of debugging - the debugger may consider it unhandled, even though it is handled.
Instead of using await, access the Task.Result property and put a try and catch around that access. You can also follow the example here and try that style.
Keep in mind that all exceptions thrown inside the context of a task thread are wrapped in an AggregateException.
The exception is not cuaght.
The reason is - when below statement is executed
await Task.Run(() => {
throw new Exception("Bang!");
});
its on a separate thread. The exception raised on that thread goes uncaught.
change it to look like as below
await Task.Run(() => {
try
{
throw new Exception("Bang!");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
});

How do I overload function to accept both async and synchronized version of callback parameter

public static T SyncVer<T>(Func<T> callback)
{
using (new LogContext("new logging context"))
{
try
{
return callback();
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
}
public static async Task<T> AsyncVer<T>(Func<Task<T>> callback)
{
using (new LogContext("new logging context"))
{
try
{
return await callback();
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
}
Please consider the code above. You may see most of the code in both functions is the same. I am searching for a way to group them up by overloading them into one so that I don't need to duplicate the content.
Is there a way to take out the similar part of both functions?
Any help provided will be appreciated. Thanks in advance.
Note that Task.FromResult will allocate, and GetAwaiter().GetResult() may dead lock
Personally I would just create two methods and not worry about it.
However, another (and slightly safer) approach is to wrap your callbacks in a ValueTask. ValueTasks work best if they execute synchronously, however they have a few subtle limitations and should never be awaited more than once.
The assumption is, this is all about creation an awaitable and non awaitable delegate overload, code reuse, and awaiting the sync version of this call is not a problem for you.
Given
public static async ValueTask<T> SomethingAsync<T>(Func<T> callback)
=> await SomethingAsync(() => new ValueTask<T>(callback()));
public static async ValueTask<T> SomethingAsync<T>(Func<Task<T>> callback)
=> await SomethingAsync(() => new ValueTask<T>(callback()));
public static async ValueTask<T> SomethingAsync<T>(Func<ValueTask<T>> callback)
{
using (new LogContext("new logging context"))
{
try
{
return await callback();
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
}
Usage
public static string DoSomething()
{
Console.WriteLine("execute sync");
return "sync result";
}
public static async Task<string> DoSomethingAsync()
{
Console.WriteLine("Execute async");
await Task.Delay(100);
return "async result";
}
...
Console.WriteLine(await SomethingAsync(DoSomething));
Console.WriteLine(await SomethingAsync(DoSomethingAsync));
Output
Create
execute sync
Dispose
sync result
Create
Execute async
Dispose
async result
To add some more efficiencies you can elide wrappers
Exmaple
public static ValueTask<T> SomethingAsync<T>(Func<T> callback)
{
try
{
return SomethingAsync(() => new ValueTask<T>(callback()));
}
catch (Exception e)
{
return ValueTask.FromException<T>(e);
}
}
public static ValueTask<T> SomethingAsync<T>(Func<Task<T>> callback)
{
try
{
return SomethingAsync(() => new ValueTask<T>(callback()));
}
catch (Exception e)
{
return ValueTask.FromException<T>(e);
}
}
Note : ValueTask.FromException is only available for .NET 5.0+
The benefits of this approach :
Less allocations for the sync version of this method.
There is no chance of a deadlock
It doesn't block on async method
It gives you a Value Task overload
The downsides are
You need to wrap the async task in a ValueTask, though it's only a stack allocation
You will need to create two overloads per method (in total three signatures)
Neither version will can be awaited twice.
The sync version is slightly slower as it creates a statemachine
Note : I personally have never had a need to do this, I would just create the two methods ¯\_(ツ)_/¯.
Additional resources
Don't Block on Async Code
Prefer ValueTask to Task, always; and don't await twice
I would try something like this:
public static T SyncVer<T>(Func<T> callback)
{
return AsyncVer(() => Task.FromResult(callback())).GetAwaiter().GetResult();
}

How to await an async delegate correctly?

While in sync world, I have a TryExecute function to wrap try/catch/log logic for reuse, like this:
TryExecute(() => SyncFunction());
private static void TryExecute(Action action)
{
try
{
action();
}
catch (Exception ex)
{
Log(ex);
throw;
}
}
I don't understand how to rewrite it into async/await pattern.
As what I understand, I have five valid ways to rewrite it into async/await (ignore any other Visual Studio has warning).
Using original sync TryExecute() with async delegate:
(1) TryExecute(async () => await AsyncFunction());
It seems not waiting anymore, the TryExecute() passes without waiting AsyncFunction() to finished.
Rewrite to a new sync TryExecuteTask() returns Task, call it with or without async delegate:
(2) await TryExecuteTask(() => AsyncFunction());
(3) await TryExecuteTask(async () => await AsyncFunction());
private static Task TryExecuteTask(Func<Task> asyncAction)
{
try
{
return asyncAction();
}
catch (Exception ex)
{
Log(ex);
throw;
}
}
Or rewrite to a new async TryExecuteAsync(), call it with or without async delegate:
(4) await TryExecuteAsync(() => AsyncFunction());
(5) await TryExecuteAsync(async () => await AsyncFunction());
private async static Task TryExecuteAsync(Func<Task> asyncAction)
{
try
{
await asyncAction();
}
catch (Exception ex)
{
Log(ex);
throw;
}
}
But if I throw Exception from inside AsyncFunction(), then none of above five ways can catch Exception. All stopped with unhandled exception. Only catch without delegate works:
(0) try
{
await AsyncFunction();
}
catch (Exception ex)
{
Log(ex);
}
That means I can't use any forms of TryExecute() from (1) to (5) to reuse the try/catch/log logic, I can only repeating try/catch/log everywhere like (0).
My whole Console code is following:
class Program
{
async static Task Main(string[] args)
{
// Original sync way
TryExecute(() => SyncFunction());
Console.WriteLine("0");
try
{
await AsyncFunction();
}
catch (Exception ex)
{
Log(ex);
}
////Console.WriteLine("1");
////TryExecute(async () => await AsyncFunction());
////Console.WriteLine("2");
////await TryExecuteTask(() => AsyncFunction());
////Console.WriteLine("3");
////await TryExecuteTask(async () => await AsyncFunction());
////Console.WriteLine("4");
////await TryExecuteAsync(() => AsyncFunction());
////Console.WriteLine("5");
////await TryExecuteAsync(async () => await AsyncFunction());
Console.WriteLine("Finished without unhandled exception.");
}
private static void SyncFunction()
{
Console.WriteLine("SyncFunction starting");
Thread.Sleep(500);
Console.WriteLine("SyncFunction starting");
throw new Exception();
}
private async static Task AsyncFunction()
{
Console.WriteLine("AsyncFunction starting");
await Task.Run(() =>
{
Console.WriteLine("Sleep starting");
Thread.Sleep(500);
Console.WriteLine("Sleep end");
throw new Exception();
});
Console.WriteLine("AsyncFunction end");
}
private static void TryExecute(Action action)
{
try
{
action();
}
catch (Exception ex)
{
Log(ex);
}
}
private static Task TryExecuteTask(Func<Task> asyncAction)
{
try
{
return asyncAction();
}
catch (Exception ex)
{
Log(ex);
throw;
}
}
private async static Task TryExecuteAsync(Func<Task> asyncAction)
{
try
{
await asyncAction();
}
catch (Exception ex)
{
Log(ex);
throw;
}
}
private static void Log(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Because of the unhandled exception, I can only comment out all pieces but one in Main() to test every case.
Calling await TryExecuteAsync(AsyncFunction) works like you would expect:
class Program
{
async static Task Main(string[] args)
{
await TryExecuteAsync(AsyncFunction);
Console.WriteLine("Finished without unhandled exception.");
}
private async static Task AsyncFunction()
{
Console.WriteLine("AsyncFunction starting");
await Task.Run(() =>
{
Console.WriteLine("Sleep starting");
Thread.Sleep(3000);
Console.WriteLine("Sleep end");
throw new Exception();
});
Console.WriteLine("AsyncFunction end");
}
private async static Task TryExecuteAsync(Func<Task> asyncAction)
{
try
{
await asyncAction();
}
catch (Exception ex)
{
Log(ex);
throw;
}
}
private static void Log(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
AsyncFunction() raises an exception that is logged and then rethrown in TryExecuteAsync. If you want to catch the rethrown exception, you should put a try/catch around the call to TryExecuteAsync:
async static Task Main(string[] args)
{
try
{
await TryExecuteAsync(AsyncFunction);
Console.WriteLine("Finished without unhandled exception.");
}
catch (Exception ex)
{
Console.WriteLine("Failed to execute: " + ex.Message);
}
}
I don't understand how to rewrite it into async/await pattern.
When converting to async, the first step is to convert what your method calls. In this case, the delegate should be converted to an async-compatible delegate first.
Action is a delegate that takes no parameters and has no return value, like void Method(). An asynchronous method that takes no parameters and has no return value looks like async Task Method(), so its delegate type would be Func<Task>.
Side note: it's especially important when dealing with delegates to remember that async void is unnatural and should be avoided.
Once you change your delegate type from Action to Func<Task>, you can await its return value, which causes your TryExecute method to be changed to async Task, as such:
private static async Task TryExecuteAsync(Func<Task> asyncAction)
{
try
{
await asyncAction();
}
catch (Exception ex)
{
Log(ex);
throw;
}
}
none of above five ways can catch Exception. All stopped with unhandled exception.
That's actually just a side effect of running the code in the debugger. With asynchronous code, you do sometimes see "unhandled" exceptions that are not actually unhandled. This is because it's the compiler-generated code that is catching the exception and placing it on the task, where it will later be re-raised when your code awaits it and then your code will catch it. The debugger gets a bit freaked out when the original exception caught by something other than your code (it's caught by the compiler generated code), and it has no way of knowing that this is perfectly normal.
So if you just continue past the debugger's "unhandled" exception, you'll see it works just fine.

async Exception not being caught

I have a windows service that references the following code. My code that uses the below method contains a try..catch block but it doesn't seem to catch RefereshTokenException that is thrown in the below method. Obviously my understanding of async is not correct.
private async void RefreshTokens()
{
try
{
var cognito = new CognitoApi();
var response = cognito.TokenRefresh(_refreshToken);
if (response.HttpStatusCode == HttpStatusCode.OK)
{
_idToken = new AwsToken(response.AuthenticationResult.IdToken);
_accessToken = new AwsToken(response.AuthenticationResult.AccessToken);
}
else
{
await _signIn(_credentials.SiteId, _credentials.LocationId, null);
}
}
catch (NotAuthorizedException)
{
await _signIn(_credentials.SiteId, _credentials.LocationId, null);
}
catch (Exception ex)
{
throw new RefreshTokenException("Failed refreshing tokens.", ex);
}
}
This is the code that calls RefreshTokens
public async void Process(QueueMessage queueMessage, Action<QueueMessage> retryAction)
{
_processingCounter.Increment();
try
{
......
IAwsToken idToken = authenticationService.Tokens.IdToken; //This is the code that calls "RefreshTokens" method
........
}
catch (Exception ex)
{
//Code never reaches here...
_logger.Error("Error in ProcessMessage", ex);
}
_processingCounter.Decrement();
}
This is an async void. One of the main reasons to avoid async void methods is that you cannot handle the exceptions they throw.
Make it an async Task and await it in the caller.
Note that you then have the same issue in that caller, async void Process(...)
Make that an async Task as well and work your way up. async/await should form a chain, from your GUI or Controller down to an async I/O call.

Why can't I catch an exception from async code?

Everywhere I read it says the following code should work, but it doesn't.
public async Task DoSomething(int x)
{
try
{
// Asynchronous implementation.
await Task.Run(() => {
throw new Exception();
x++;
});
}
catch (Exception ex)
{
// Handle exceptions ?
}
}
That said, I'm not catching anything and get an "unhandled exception" originating at the 'throw' line. I'm clueless here.
You have the "Just my code" Option turned on. With this on, it is considering the exception unhandled with respect to "just your code"--because other code is catching the exception and stuffing it inside of a Task, later to be rethrown at the await call and caught by your catch statement.
Without being attached in the debugger, your catch statement will be triggered, and it will run as you expect. Or you can just continue from within the debugger and it will run as expected.
The better thing to do is to just turn off "Just my code". IMO, it causes more confusion than it is worth.
As SLaks said, your code works fine.
I strongly suspect you over-simplified your example, and have an async void in your code.
The following works fine:
private static void Main(string[] args)
{
CallAsync();
Console.Read();
}
public static async void CallAsync()
{
try
{
await DoSomething();
}
catch (Exception)
{
// Handle exceptions ?
Console.WriteLine("In the catch");
}
}
public static Task DoSomething()
{
return Task.Run(() =>
{
throw new Exception();
});
}
The following doesn't work:
private static void Main(string[] args)
{
CallAsync();
Console.Read();
}
public static void CallAsync()
{
try
{
DoSomething();
}
catch (Exception)
{
// Handle exceptions ?
Console.WriteLine("In the catch");
}
}
public static async void DoSomething()
{
await Task.Run(() =>
{
throw new Exception();
});
}
See http://msdn.microsoft.com/en-us/magazine/jj991977.aspx
Async void methods have different error-handling semantics. When an
exception is thrown out of an async Task or async Task method, that
exception is captured and placed on the Task object. With async void
methods, there is no Task object, so any exceptions thrown out of an
async void method will be raised directly on the
SynchronizationContext that was active when the async void method
started. Figure 2 illustrates that exceptions thrown from async void
methods can’t be caught naturally.
Your code won't even compile cleanly at the moment, as the x++; statement is unreachable. Always pay attention to warnings.
However, after fixing that, it works fine:
using System;
using System.Threading.Tasks;
class Test
{
static void Main(string[] args)
{
DoSomething(10).Wait();
}
public static async Task DoSomething(int x)
{
try
{
// Asynchronous implementation.
await Task.Run(() => {
throw new Exception("Bang!");
});
}
catch (Exception ex)
{
Console.WriteLine("I caught an exception! {0}", ex.Message);
}
}
}
Output:
I caught an exception! Bang!
(Note that if you try the above code in a WinForms app, you'll have a deadlock because you'd be waiting on a task which needed to get back to the UI thread. We're okay in a console app as the task will resume on a threadpool thread.)
I suspect the problem is actually just a matter of debugging - the debugger may consider it unhandled, even though it is handled.
Instead of using await, access the Task.Result property and put a try and catch around that access. You can also follow the example here and try that style.
Keep in mind that all exceptions thrown inside the context of a task thread are wrapped in an AggregateException.
The exception is not cuaght.
The reason is - when below statement is executed
await Task.Run(() => {
throw new Exception("Bang!");
});
its on a separate thread. The exception raised on that thread goes uncaught.
change it to look like as below
await Task.Run(() => {
try
{
throw new Exception("Bang!");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
});

Categories

Resources