Handle exception + await - c#

I have the following code:
try
{
await Task.Run(() => myAppClient.CreateResourceRecord());
}
catch (MyApplicationException dnsException)
{
// Exception code
}
The MyApplicationException is thrown during myAppClient.CreateResourceRecord() but it is not caught in the catch (MyApplicationException dnsException) statement.
How can it be solved?

Based on #usr's comments:
As can be seen by running this small but complete console application example, the exception does get caught.
class Program
{
static void Main(string[] args)
{
var t = foo();
t.Wait();
Console.ReadKey();
}
class MyApplicationException : Exception { }
static async Task foo()
{
try
{
await Task.Run(() => { throw new MyApplicationException(); });
Console.WriteLine("Completed without exception");
}
catch (MyApplicationException)
{
Console.WriteLine("Exception caught");
}
}
}
Output:
Exception caught
See: http://dotnetpad.net/ViewPaste/dJQgaYiqtEqqGTCiZJjdgw

Remember that Task works in another thread so exception also is thrown in another thread. To catch exception from Task try something like this:
try
{
await Task.Run(() => myAppClient.CreateResourceRecord());
}
catch (AggregateException ae)
{
ae.Handle((x) =>
{
if (x is MyApplicationException)
{
// Exception code
}
});
}

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

Why isn't an Exception Caught when Thrown Out of Task.WhenAll?

The issue I'm having is that the an exception (marked below) is not being caught when thrown into the catch statement surrounding Task.WhenAll. I'm not sure why this exception is ballooning up to the call stack.
I read the following article that states a try/catch wrapping an awaited Task.WhenAll will catch the first exception thrown out of it, but that doesn't seem to be the case for me....
I have the following code snippet below (you can copy and paste it and just hit 'Run') to reproduce (.netcoreapp2.1).
using System;
using System.Threading.Tasks;
using System.Threading;
namespace TestProgram
{
class Program
{
public static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
private static async Task MainAsync(string[] args)
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
var thread = new Thread(() => CancelToken(tokenSource));
thread.IsBackground = true;
thread.Start();
var ourTask = SpinUntilCancelled(token);
try
{
await Task.WhenAll(ourTask);
}
catch (Exception ex) // NOT CATCHING AND PRINTING!
{ Console.WriteLine($"{ex}"); }
}
private static void CancelToken(CancellationTokenSource obj)
{
Thread.Sleep(5000);
obj.Cancel();
obj.Dispose();
return;
}
private static Task SpinUntilCancelled(CancellationToken cancellation)
{
int i = 0;
while (true)
{
try
{
if (cancellation.IsCancellationRequested)
throw new ApplicationException("Token cancelled");
Thread.Sleep(1000);
Console.WriteLine($"Text {++i}");
}
catch
{
Console.WriteLine("Cancelled!");
cancellation.ThrowIfCancellationRequested();
}
}
}
}
}
As you can see, my breakpoint is not being hit.
Because of the while (true) and the lack of a break or return statement, the SpinUntilCancelled method never produces a value, so its return type is irrelevant. To make it produce an actual Task that you can later await, you should give it a proper asynchronous implementation, like this:
private static async Task SpinUntilCancelled(CancellationToken cancellationToken)
{
int i = 0;
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
await Task.Delay(1000, cancellationToken);
Console.WriteLine($"Text {++i}");
}
}
As a side note, if you want to get an instant notification when the CancellationTokenSource is canceled, you can Register a callback to its Token like this:
var tokenSource = new CancellationTokenSource();
tokenSource.Token.Register(() => Console.WriteLine("Token canceled"));

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.

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