async Exception not being caught - c#

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.

Related

Why I couldn't catch the exception in async function that has void return type?

static void Main(string[] args) {
try {
var a = MyMethodAsync();
a.Wait(); // calling Wait throw an AggregateException
}
catch (Exception e) {
Console.WriteLine("Catch");
}
Console.ReadLine();
}
static async Task<String> MyMethodAsync() {
String s = await TestThrowException();
return s;
}
static Task<String> TestThrowException() {
return Task.Run(() => {
throw new DivideByZeroException();
return "placeholder"; // return statement is needed for the compilier to work correctly
});
}
The code above works, the catch block in Main method can catch the AggregateException exception (originate from TestThrowException and get converted into AggregateException).
But if I have the code like this:
static void Main(string[] args) {
try {
MyMethodAsync();
}
catch (Exception e) {
Console.WriteLine("Catch");
}
Console.ReadLine();
}
static async void MyMethodAsync() {
await TestThrowException();
}
static Task<String> TestThrowException() {
return Task.Run(() => {
throw new DivideByZeroException();
return "placeholder";
}
then the catch block in Main method cannot catch any exception, why is that?
Any time you have async void, you're basically breaking the ability to correctly signal completion and failure; the only way it can report failure is if the exception happens immediately and before any incomplete await - i.e. synchronously. In your case, the Task.Run guarantees that this is not synchronous, hence any knowledge of the outcome and failure: is lost.
Fundamentally, never write async void (unless you absolutely have to, for example in an event-handler). In addition to the problem above, it also has known complications with some SynchronizationContext implementations (in particular the legacy ASP.NET one), which means simply invoking an async void method is enough to crash your application (at least hypothetically; the sync-context caveat applies more to library authors than application authors, since library authors don't get to choose the application execution environment).
Remove the async void. If you want to return "nothing", then you should use async Task or async ValueTask as the signature:
static async Task MyMethodAsync() {
await TestThrowException();
}
(which could perhaps also be simplified to)
static Task MyMethodAsync()
=> TestThrowException();
and:
static async Task Main(string[] args) {
try {
await MyMethodAsync();
}
catch (Exception e) {
Console.WriteLine("Catch");
}
Console.ReadLine();
}

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.

Handling async exceptions

I'm wondering how I can let this code fall in the catch of PassThrough?
using System;
using System.Threading.Tasks;
public class Program
{
public static async Task Main(string[] args)
{
try
{
await PassThrough(Test());
} catch (Exception) {
Console.WriteLine("caught at invocation");
}
Console.ReadLine();
}
public static async Task PassThrough(Task<bool> test)
{
try
{
var result = await test.ConfigureAwait(false);
// still need to do something with result here...
}
catch
{
Console.WriteLine("never caught... :(");
}
}
/// external code!
public static Task<bool> Test()
{
throw new Exception("something bad");
// do other async stuff here
// ...
return Task.FromResult(true);
}
}
fiddle
The external code should return handle the error path and return Task.FromException? Pass a Func<Task<bool>>?
My recommendation would be to change your PassThrough method to take a Func<Task<bool>> instead of a Task<bool>. This way, you can capture exceptions arising both from the synchronous part of your Test method, as well as the asynchronous task it launches. An added advantage is that asynchronous methods (defined using async and await) can be directly cast to Func<Task> or Func<Task<TResult>>.
using System;
using System.Threading.Tasks;
public class Program
{
public static async Task Main()
{
try
{
await PassThrough(Test);
// Note that we are now passing in a function delegate for Test,
// equivalent to () => Test(), not its result.
}
catch (Exception)
{
Console.WriteLine("caught at invocation");
}
Console.ReadLine();
}
public static async Task PassThrough(Func<Task<bool>> test)
{
try
{
var task = test(); // exception thrown here
var result = await task.ConfigureAwait(false);
// still need to do something with result here...
}
catch
{
Console.WriteLine("caught in PassThrough");
}
}
/// external code!
public static Task<bool> Test()
{
throw new Exception("something bad");
// do other async stuff here
// ...
return Task.FromResult(true);
}
}
Adding to Douglas's answer.
Only catch exceptions if you are able to do something meaningful with them and you can manage them at that level.
Task.FromException basically just places the exception on a task which you would usually return. However, in this case the Async Await Pattern already does this for you. i.e If you just let it fail, the exception will get placed on the task anyway, so there seems no real reason from your code to catch anything.
The only pertinent place you have to think about catching exceptions is in async void as they run unobserved and can cause issues when an exception is thrown
In the following line you are awaiting the PassThrough, not the Test.
await PassThrough(Test());
You could await both if you wanted:
await PassThrough(await Test()); // also need to change the signature of PassThrough from Task<bool> to bool.
...but in both cases the Test will be invoked first. And since it throws an exception, the PassThrough will never be invoked. This is the reason you don't see the "caught in PassThrough" message. The execution never enters this method.

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);
}
});

A good solution for await in try/catch/finally?

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).

Categories

Resources