Задачи .NET 4.0: Возврат исключения из потока пользовательского интерфейса в Task.ContinueWith - PullRequest
7 голосов
/ 04 августа 2011

У меня есть приложение WPF, где я выполняю длительный вызов WCF с использованием System.Threading.Tasks.Я перехватываю необработанные исключения, добавляя обработчик в Application.Current.DispatcherUnhandledException.

Я создаю задачу, в которой функция ContinueWith запускается в потоке пользовательского интерфейса, используя следующий код:

var task = new Task<T>(func).ContinueWith(t =>
{
    if (t.IsFaulted)
    {
        throw t.Exception.GetBaseException();
    }
    else
    {
        // Show t.Result on UI
    }
}, TaskScheduler.FromCurrentSynchronizationContext());

Когдав задаче возникает исключение, я хотел бы перебросить исключение, чтобы обработчик DispatcherUnhandledException мог обработать его.Но когда я перебрасываю исключение, как показано выше, это приводит к сбою моего приложения, и DispatcherUnhandledException не вызывается.

Как перебросить исключение в потоке пользовательского интерфейса, чтобы вызывался обработчик DispatcherUnhandledException?

Когда я использовал BackgroundWorker, перебрасывание исключения сделало именно это.По сути, я хочу заменить BackgroundWorker на Task, поскольку у Task есть несколько действительно приятных функций, которыми я бы хотел воспользоваться.

Ответы [ 2 ]

7 голосов
/ 24 августа 2011

Один из способов решить эту проблему - сбросить исключение в лямбда-выражении, содержащемся в выражении.Что-то вроде:

Exception ex = t.Exception;
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => { throw ex; }));

Я не рекомендую это, хотя это немного грязно, но это действительно отвечает на вопрос!

В качестве альтернативы вы можете сделать что-то похожее противное с SynchronizationContext.Post .

1 голос
/ 09 октября 2011

У меня точно такая же проблема, хотя в моем случае приложение не падает, но событие Application.DispatcherUnhandledException никогда не вызывается.Я также попытался использовать AppDomain.CurrentDomain.UnhandledException, который тоже не работает.Мне нравится иметь обработчик исключений верхнего уровня для обработки глобальных ошибок, которые могут возникнуть во многих местах.

У меня есть разработанная мной библиотека, использующая асинхронный шаблон на основе событий (EAP), который я изменяю навместо этого используйте асинхронный шаблон на основе задач (TAP) при подготовке к .NET 4.5, который имеет гораздо лучшую асинхронную поддержку, основанную на задачах.С EAP событие Completed выполняется в потоке пользовательского интерфейса, что приятно.Используя Задачи, вы должны использовать TaskScheduler.FromCurrentSynchronizationContext (), как вы упомянули выше.Я проверил, что код ContinueWith работает в потоке пользовательского интерфейса, и я выкидываю исключение оттуда.Итак, я в растерянности относительно того, что происходит.

Надеюсь, это будет исправлено в .NET 4.5, и, надеюсь, мне не преждевременно переходить с EAP на TAP.Мне нравится тот факт, что вы можете лучше сочинять вещи с помощью TAP.Тем не менее, необходимость вызывать Dispatcher.Invoke () во многом кажется плохой.

...