Exception thrown in async handler is not caught or handled - c#

For some reason I could not catch an exception thrown inside anonymous async delegate that subscribed to event.
It does not get caught inside TestTestAsync (I suppose because of invoke wait only fastest one) but why it is not caught in unhandled or unobserved or crash app?
ThrowUnobservedTaskExceptions = true also does not make any sense.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp5
{
class Program
{
static string lockStr = Guid.NewGuid().ToString();
public static void ConsoleWriteLine(string Message, ConsoleColor? color = null)
{
lock (lockStr)
{
var old = Console.ForegroundColor;
if (color != null)
Console.ForegroundColor = color.Value;
Console.WriteLine(Message);
if (color != null)
Console.ForegroundColor = old;
}
}
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
try
{
var cls = new TestClass();
cls.TestAsync += async (s) => await Cls_TestRealAsyncAsync(s);
cls.TestAsync += Cls_TestRealAsync;
Task.Run(async () => await cls.TestTestAsync()).Wait();
Thread.Sleep(5000);
}
catch (Exception ex)
{
ConsoleWriteLine($"{nameof(Main)}: {ex.Message}");
}
}
private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
ConsoleWriteLine($"{nameof(TaskScheduler_UnobservedTaskException)}: {(e.Exception as Exception).Message}", ConsoleColor.Yellow);
}
private static Task Cls_TestRealAsync(object sender)
{
try
{
Thread.Sleep(100);
throw new NotImplementedException($"{nameof(Cls_TestRealAsync)}");
}
catch (Exception ex)
{
ConsoleWriteLine(ex.Message, ConsoleColor.Red);
throw;
}
}
private static async Task Cls_TestRealAsyncAsync(object sender)
{
try
{
await Task.Run(() => Thread.Sleep(1000));
throw new NotImplementedException($"{nameof(Cls_TestRealAsyncAsync)}");
}
catch (Exception ex)
{
ConsoleWriteLine(ex.Message, ConsoleColor.Red);
throw;
}
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
ConsoleWriteLine($"{nameof(CurrentDomain_UnhandledException)}: {(e.ExceptionObject as Exception).Message}", ConsoleColor.Yellow);
}
}
public class TestClass
{
public delegate Task TestHandlerAsync(object sender);
public event TestHandlerAsync TestAsync;
private async Task OnTestAsync()
{
if (TestAsync != null)
await TestAsync.Invoke(this);
}
public async Task TestTestAsync()
{
try
{
await OnTestAsync();
}
catch (Exception ex)
{
Program.ConsoleWriteLine($"{nameof(TestTestAsync)}: {ex.Message}", ConsoleColor.Green);
}
}
}
}
PS: I made tests on 4.7.1

Asynchronous code is not necessarily concurrent code, but you should be careful anyway.
This:
private async Task OnTestAsync()
{
if (TestAsync != null)
await TestAsync.Invoke(this);
}
can get you in trouble because by the time TestAsync.Invoke is invoked, TestAsync can be null.
But the problem that you're trying to solve is that, not the that the fastest one is awaited but that the last one is awaited.
You should revise your API but, if you can't, try this:
public class TestClass
{
public delegate Task TestHandlerAsync(object sender);
public event TestHandlerAsync TestAsync;
private async Task OnTestAsync()
{
var testAsync = this.TestAsync;
if (testAsync == null)
{
return;
}
await Task.WhenAll(
from TestHandlerAsync d in testAsync.GetInvocationList()
select d.Invoke(this));
}
public async Task TestTestAsync()
{
try
{
await OnTestAsync();
}
catch (Exception ex)
{
Program.ConsoleWriteLine($"{nameof(TestTestAsync)}: {ex.Message}", ConsoleColor.Green);
}
}
}
if you only care to show the first exception.
Or:
public class TestClass
{
public delegate Task TestHandlerAsync(object sender);
public event TestHandlerAsync TestAsync;
private async Task<Exception[]> OnTestAsync()
{
var testAsync = this.TestAsync;
if (testAsync == null)
{
return new Exception[0];
}
return await Task.WhenAll(
from TestHandlerAsync d in testAsync.GetInvocationList()
select ExecuteAsync(d));
async Task<Exception> ExecuteAsync(TestHandlerAsync d)
{
try
{
await d(this);
return null;
}
catch (Exception ex)
{
return ex;
}
}
}
public async Task TestTestAsync()
{
try
{
var exceptions = await OnTestAsync();
foreach (var exception in exceptions)
{
if (exception != null)
{
Program.ConsoleWriteLine($"{nameof(TestTestAsync)}: {exception.Message}", ConsoleColor.Green);
}
}
}
catch (Exception ex)
{
Program.ConsoleWriteLine($"{nameof(TestTestAsync)}: {ex.Message}", ConsoleColor.Green);
}
}
}
if you care for all.

Found the answer. It not abandoned. It simply still not fired because of life of my test console was too short.
Unhandled exception will be thrown at GC.Collect()
https://blogs.msdn.microsoft.com/ptorr/2014/12/10/async-exceptions-in-c/
During GC, it notices that nobody ever checked the result (and
therefore never saw the exception) and so bubbles it up as an
unobserved exception.
So next code before main method end will solve issue and I see exception
GC.Collect();
Thread.Sleep(5000);

Related

Cannot throw an exception in catch block

I Have a class, that should not show any dialogs to final user. In case, that user passed wrong filepath, i tried to throw and exception and handle it in proper class.
However, despite 'throw' instruction, Visual Studio shows Exception Dialog and breaks application after it occurs (Debuging mode). In Release mode application just crashes after giving wrong filepath. What am i doing wrong?
GuyManager.cs:
private IStorageFile latestGuyFile;
public IStorageFile LatestGuyFile { get { return latestGuyFile; } }
public string Path { get; set; }
public async void ReadGuyAsync()
{
if (String.IsNullOrWhiteSpace(Path))
return;
try
{
latestGuyFile = await StorageFile.GetFileFromPathAsync(Path);
}
catch (Exception ex)
{
Debug.WriteLine("Error occured: " +ex.Message);
Debug.WriteLine(ex.StackTrace);
throw;
}
MainPage.xml.cs:
private async void loadGuy_Click(object sender, RoutedEventArgs e)
{
try
{
guyManager.ReadGuyAsync();
}
catch (Exception ex)
{
MessageDialog dialog = new MessageDialog("Error" + ex.Message);
await dialog.ShowAsync();
}
}
I see a problem in your Click event handler.
You define it as async, but you are not awaiting anything.
You should change the ReadGuyAsync method to return a Task instead of void, like this:
public async Task ReadGuyAsync()
and in the loadGuy_Click method, you should await it:
await guyManager.ReadGuyAync();

How to catch two exceptions in one stack when use using

class Program
{
static void Main(string[] args)
{
try
{
using (var ss = new extest()) {
throw new Exception("Exception1");
}
}
catch(Exception ex)
{
System.Console.WriteLine(ex.Message);
}
}
}
class extest : IDisposable
{
public void Dispose()
{
throw new Exception("Exception2");
}
}
Run the codes result is "Exception2",
So I want to know how you can catch two exceptions, or just catch an Exception1.
My project has thousands of such using, which does not add try, but extest's Dispose is only one place, and I hope to know what exception has thrown before the Dispose.
Thanks
The problem in your example is that the second exception is thrown while the first exception is being handled. I.e. the using statement is effectively a try/finally pair, with the call to Dispose() in the finally block. So, the second exception supersedes the first one.
Having a Dispose() method that throws an exception is a very bad idea. So, the best solution here is to fix that. Don't throw an exception from a Dispose() method. But if you can't fix that for some reason and you want to see both, you need to make sure you're in a position to catch both. You can do this by adding another try/catch inside the using:
try
{
using (var ss = new extest()) {
try
{
throw new Exception("Exception1");
}
catch (Exception exInner)
{
System.Console.WriteLine(ex.Message);
throw;
}
}
}
catch(Exception ex)
{
System.Console.WriteLine(ex.Message);
}
The easiest way to handle this would be to rearrange your code:
static void Main(string[] args)
{
try
{
using (var ss = new extest())
{
try
{
CodeThatMightThrowAnException();
}
catch (Exception e)
{
// Process Exception here
}
}
}
catch(Exception ex)
{
System.Console.WriteLine(ex.Message);
}
}
Edit:
If the handling of the exceptions inside the using is always going to be the same, you could build a helper class that could make refactoring easier:
public class TryCatchHelper
{
public Exception Exception { get; private set; } = null;
public void Execute(Action action)
{
try
{
action()
}
catch (Exception e)
{
exception = e;
}
}
}
Then in your method:
static void Main(string[] args)
{
var helper = new TryCatchHelper();
try
{
using (var ss = new extest())
{
helper.Execute(() => {
// Your Code Block Here
});
}
}
catch(Exception ex)
{
// The Dispose threw an exception
}
if (helper.Exception != null)
{
// Handle the exception from the block here.
}
}
it's impossible to catch more than 1 exception.
when you throw Exception2 it should be catched in your catch clause. when you see "Exception2" it is printed by System.Console.WriteLine(ex.Message);. So, you can change the log in catch, or change the throwing exception message in Dispose.
reference added:
class Program
{
static void Main(string[] args)
{
try
{
using (var ss = new extest()) {
...
}
}
catch(Exception ex)
{
System.Console.WriteLine("extest error : " + ex.Message);
}
}
}
class extest : IDisposable
{
public void Dispose()
{
throw new Exception("Dispose failed: reason");
}
}

How to stop task in pararell foreach loop when exception occurs?

I need to know how to stop task in pararell foreach loop when exception occurs? If Foo1() thrown an exception DoSomeWork() should be cancelled.
Item class
class Item
{
public async Task DoSomeWork()
{
try
{
await Foo1();
await Foo2();
}
catch (Exception ex)
{
Console.Writeline(ex.Message);
}
}
private async Task Foo1()
{
try
{
//
// some functionality
//
}
catch(Exception ex)
{
// If exception occurs, then how cancel Task DoSomeWork()
}
}
private async Task Foo2()
{
try
{
//
// some functionality
//
}
catch(Exception ex)
{
// If exception occurs, then how cancel Task DoSomeWork()
}
}
}
and the ItemCollection class with Pararell.Foreach loop
class ItemCollection
{
public void StartAsync()
{
try
{
IList<Task> il = new List<Task>();
Parallel.ForEach(ListOfItems, t => il.Add(t.DoSomeWork()));
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
How to use the CancellationToken property in this example?
Here is a good example from MSDN: https://msdn.microsoft.com/de-de/library/ee256691(v=vs.110).aspx
Before the loops starts:
CancellationTokenSource cts = new CancellationTokenSource();
ParallelOptions po = new ParallelOptions();
po.CancellationToken = cts.Token;
Inside the loop:
Parallel.ForEach(nums, po, (num) =>
{
// Do some work here
po.CancellationToken.ThrowIfCancellationRequested();
});
From another thread, you can trigger the cancel event:
cts.Cancel();

Catching exceptions from async-await when void is the return value

I find myself using async fire-and-forget methods using void as the return value, but DO care about exceptions.
It seems to be the consensus that exceptions cannot be handled properly with async-await if no reference is hold to the executing Task and void should be.. well.. avoided..
What am I missing in the following code that apparently seems to do the job:
class Program
{
static void Main()
{
var p = new Processor();
p.ExceptionThrown += p_ExceptionThrown;
for (var i = 0; i < 10; i++)
p.ProcessAsync(i);
Console.ReadKey();
}
static void p_ExceptionThrown(object sender, Exception e)
{
Console.WriteLine("Exception caught in Main : " + e);
}
}
class Processor
{
public async void ProcessAsync(int iteration)
{
try
{
await Task.Run(() => Process(iteration));
}
catch (Exception e)
{
OnException(e);
}
}
public void Process(int iteration)
{
Thread.Sleep(500);
if(iteration == 5)
throw new Exception("AUUCH");
}
public event EventHandler<Exception> ExceptionThrown;
void OnException(Exception e)
{
var handler = ExceptionThrown;
if (handler != null)
handler(this, e);
}
}
Under the covers the async / await keywords actually generate a state-machine when they are compiled down to IL, please read about it here. The only time that you should ever use async void is on an event handler, as explained here. The issue is that when the state machine is built-out it uses the Task or Task<T> classes as the return type in order to manage the next state of the next asynchronous operation in the chain. However, when you define the method as void, it basically returns null to the state machine and then everything gets out of whack.
Exceptions from an async void can’t be caught with catch
The quote from above is from the best practices article I pointed you to before. The below alteration does work, as I have tested it to verify that it does.
class Program
{
static void Main()
{
var p = new Processor();
p.ExceptionThrown += p_ExceptionThrown;
for (var i = 0; i < 10; i++)
p.ProcessAsync(i);
Console.ReadKey();
}
static void p_ExceptionThrown(object sender, Exception e)
{
Console.WriteLine("Exception caught in Main : " + e);
}
}
class Processor
{
public async Task ProcessAsync(int iteration)
{
try
{
await Task.Run(() => Process(iteration));
}
catch (Exception e)
{
OnException(e);
}
}
public void Process(int iteration)
{
Thread.Sleep(500);
if(iteration == 5)
throw new Exception("AUUCH");
}
public event EventHandler<Exception> ExceptionThrown;
void OnException(Exception e)
{
var handler = ExceptionThrown;
if (handler != null)
handler(this, e);
}
}

Wpf handling exception throwing by task

How can i handle an exception on wpf, that was throwed within worker thread?
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
var task = Task.Factory.StartNew(() =>
{
Debug.WriteLine("Hello");
throw new Exception();
});
try
{
task.Wait();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
}
Or it is not common to handle an exception in this way?
task.ContinueWith(task => {
if (task .Exception != null)
{
//.........
}
},TaskContinuationOptions.OnlyOnFaulted);
Take a look here http://www.codeproject.com/Articles/152765/Task-Parallel-Library-of-n#handlingExceptions
You can catch the [System.AggregateException] to examine if you can handle any of its InnerExceptions. See the example below.
var task = Task.Factory.StartNew(() =>
{
Debug.WriteLine("Hello");
throw new InvalidOperationException(); // throw an InvalidOperationException that is handled.
});
try
{
task.Wait();
}
catch (AggregateException ae)
{
ae.Handle((x) =>
{
if (x is InvalidOperationException) // We know how to handle this exception.
{
Console.WriteLine("InvalidOperationException error.");
return true; // Continue with operation.
}
return false; // Let anything else stop the application.
});
}

Categories

Resources