The following code does not catch my OperationCancelException which is thrown by calling ct.ThrowIfCancellationRequested
.
public partial class TitleWindow : Window, IAsyncInitialization
{
public Task Initialization{get; private set;}
CancellationTokenSource cts;
public TitleWindow()
{
InitializeComponent();
cts = new CancellationTokenSource();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
cts.Cancel();
Initialization = GetCancelExceptionAsync(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Operation canceled!");
}
}
public async Task GetCancelExceptionAsync(CancellationToken ct)
{
await Task.Delay(1000);
ct.ThrowIfCancellationRequested();
}
}
However if i replace my Window_Loaded
method with the following (making it async and await the call of my async method), the exception gets caught.
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
cts.Cancel();
await GetCancelExceptionAsync(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Operation canceled!");
}
}
Why is my first approach not working? Is the exception not properly propagated to the correct synchronization context?
I was trying to use The Asynchronous Initialization Pattern
described in Stephen Clearys blog post to be able to later on await a task which was started in a constructor (and in order to make it comparable to my second example I used the (async
) Window_Loaded
event to await methods there right away, like suggested to me in a previous question). Then I wanted to provide an option to cancel the async method that I started in the constructor, where i am currently stuck because the exception handling does not work as I expected.
With my "non-working" code, I can catch the exception by putting await Initialization
in a try-catch block somewhere, but I still get an additional unhandled exception.
How do I implement this in a way that allows me to await my async method later on (to ensure that I do not work with an inconsistent state of my object) and still being able to cancel that long-running Task (which would of course need to return/set default values)?
Exeption is thrown in the task on another thread.
In your first example the exception is not caught because it does not occure before leaving the
try/catch
block. If you want to catch it there you need to wait/await
it there exactly like you do in the second example. If you do not await the returned task the method continues execution and leaves thetry/catch
block before the exception actually occures...If you want to catch the exception "out of band" you can also register to
TaskScheduler.UnobservedTaskException
(this event is called if a task is throwing an exception which is nowhere caught) to get all uncaught exceptions or monitor the tasksException
property. May also check out THIS answer.