1

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)?

Community
  • 1
  • 1
H W
  • 2,556
  • 3
  • 21
  • 45
  • 1
    If you do not await the task, execution has left the try/catch well before the exception is thrown. The await turns the rest of the method into a continuation so that it can be executed when the task completes. – Wayne Tanner Feb 20 '15 at 12:55
  • Problem lies in the fact that if you do not await the Task in your Try-block, when it finishes, it'll be outside the try-scope. Meaning that it wont catch it. What you would probably do is use the 'ContinueWith' on the Task. It takes 1 parameter, namely the Task. And you can then grab the Task.Exception property and use it however – Falgantil Feb 20 '15 at 13:08

2 Answers2

3

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 the try/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 tasks Exception property. May also check out THIS answer.

Community
  • 1
  • 1
Christoph Fink
  • 22,727
  • 9
  • 68
  • 113
1

Exeption is thrown in the task on another thread.

public async Task GetCancelExceptionAsync(CancellationToken ct)
        {
            try
            {
                await Task.Delay(1000);
                ct.ThrowIfCancellationRequested();
            }
            catch (Exception e)
            {
                // your Cancleation expeption
            }
        }