Reputation: 180
I want to suppress exception triggered in the task. As I recall, some time ago I used this code to make it possible:
void Main(..)
{
Task Fail()
{
throw new Exception("ex");
}
Fail().ContinueWith(t =>
{
var ignored = t.Exception;
ignored?.Handle(e => true);
},
TaskContinuationOptions.OnlyOnFaulted |
TaskContinuationOptions.ExecuteSynchronously);
}
I see that when I run this in Console application (.NET 6) now, the only logic happens is making thrown exception (t.Exception
) "observed" and then, this actually triggered exception is being pushed to the main method (outside task) and crashes my application.
Adding await
like:
await (Fail().ContinueWith(..))
doesn't make difference.
I'm not sure why I remember it worked before, but any ideas how to make this logic?
Upvotes: 0
Views: 689
Reputation: 43911
The problem with your code is that the Fail()
method fails to create a Task
, and instead it throws synchronously an exception. The .ContinueWith
is irrelevant. A continuation is never attached to a Task
, because a Task
was never created in the first place. You can't suppress exceptions triggered in a task, if you don't have a Task
to begin with.
In order to suppress synchronous exceptions thrown by method calls, the most primitive tool to use is the try
statement with an empty catch
block:
try { Fail(); } catch { }
Upvotes: 1
Reputation: 457302
As I explain on my blog, all async
methods begin executing synchronously. The async
keyword transforms your method into a state machine, including code that catches thrown exceptions and places them on the returned task. Without the async
keyword, the method is just like any other method, and the exception is thrown directly.
To fix, add the async
keyword:
async Task Fail()
{
throw new Exception("ex");
}
Upvotes: 2
Reputation: 565
You don't await Fail()
method at the beginning. It runs before you chain with with ContinueWith
method. If you add some delay to beginning, like few hundred milliseconds, you will see that your code is working;
async Task Fail()
{
await Task.Delay(500);
throw new Exception("ex");
}
await Fail().ContinueWith(t =>
{
var ignored = t.Exception;
ignored?.Handle(e => true);
Console.WriteLine($"Exception Handled: {t.Exception.Message}");
}, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
But to prevent that and not use that dirty "trick" to solve your "problem", you need to use Task.Run()
method and chain it with ContinueWith
method;
Task Fail()
{
throw new Exception("ex");
}
await Task.Run(Fail).ContinueWith(t =>
{
var ignored = t.Exception;
ignored?.Handle(e => true);
Console.WriteLine($"Exception Handled: {t.Exception.Message}");
}, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
If you want to keep your Main()
method void
, instead of making it async Task Main()
, remove the await
keyword and add these two methods to the end of ContinueWith
method;
GetAwaiter().GetResult()
Upvotes: 1