HttpClient.SendAsync() Exception [duplicate] - c#

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

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

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.

Different behavior of exception with async method

Supposed you have 2 async method define as bellow:
public async Task<TResult> SomeMethod1()
{
throw new Exception();
}
public async Task<TResult> SomeMethod2()
{
await Task.Delay(50);
throw new Exception();
}
Now if you await on those 2 methods the behavior will be pretty much the same. But if you are getting the task the behavior is different.
If I want to cache the result of such a computation but only when the task run to completion.
I have to take care of the 2 situation:
First Situation:
public Task<TResult> CachingThis1(Func<Task<TResult>> doSomthing1)
{
try
{
var futur = doSomthing1()
futur.ContinueWith(
t =>
{
// ... Add To my cache
},
TaskContinuationOptions.NotOnFaulted);
}
catch ()
{
// ... Remove from the pending cache
throw;
}
}
Second Situation
public Task<TResult> CachingThis2(Func<Task<TResult>> doSomthing)
{
var futur = SomeMethod2();
futur.ContinueWith(
t =>
{
// ... Add To my cache
},
TaskContinuationOptions.NotOnFaulted);
futur.ContinueWith(
t =>
{
// ... Remove from the pending cache
},
TaskContinuationOptions.OnlyOnFaulted);
}
Now I pass to my caching system the method that will execute the computation to cache.
cachingSystem.CachingThis1(SomeMethod1);
cachingSystem.CachingThis2(SomeMethod2);
Clearly I need to duplicate code in the "ConinueWith on faulted" and the catch block.
Do you know if there is a way to make the exception behave the same whether it is before or after an await?
There's no difference in the exception handling required for both SomeMethod1 and SomeMethod2. They run exactly the same way and the exception would be stored in the returned task.
This can easily be seen in this example;
static void Main(string[] args)
{
try
{
var task = SomeMethod1();
}
catch
{
// Unreachable code
}
}
public static async Task SomeMethod1()
{
throw new Exception();
}
No exception would be handled in this case since the returned task is not awaited.
There is however a distinction between a simple Task-returning method and an async method:
public static Task TaskReturning()
{
throw new Exception();
return Task.Delay(1000);
}
public static async Task Async()
{
throw new Exception();
await Task.Delay(1000);
}
You can avoid code duplication by simply having an async wrapper method that both invokes the method and awaits the returned task inside a single try-catch block:
public static async Task HandleAsync()
{
try
{
await TaskReturning();
// Add to cache.
}
catch
{
// handle exception from both the synchronous and asynchronous parts.
}
}
In addition to what I3arnon said in his answer, in case you ContinueWith on async method without the TaskContinuationOptions you specify, exception captured by the Task parameter you receive in the continuation handler can be handled in the following way:
SomeMethod1().ContinueWith(ProcessResult);
SomeMethod2().ContinueWith(ProcessResult);
With ProcessResult handler which looks like:
private void ProcessResult<TResult>(Task<TResult> task)
{
if (task.IsFaulted)
{
//remove from cahe
}
else if (task.IsCompleted)
{
//add to cache
}
}

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