http://msdn.microsoft.com/en-us/magazine/gg598924.aspx
예외가 WPF Dispatcher.Invoke에 전파되지 않는 이유는 무엇입니까?
작업 예외가 UI 스레드로 다시 전파되도록 허용하려면 어떻게합니까?
아래의 코드에서 나는 예외에 던져진 예외 사항을 LogException이 처리 할 UI 스레드로 되돌려 보내야합니다. 라인을 따라 어딘가에서 예외를 다시 던질 필요가 있다면 저와 잘 맞는 것입니다. 어쨌든. 어떻게해야합니까?
내 질문과 비슷하지만 내 앱과 관련된 답변이 표시되지 않습니다.
3 편집 :단순화 된 예제 게시
편집 2 :이것 좀 봐:http://msdn.microsoft.com/en-us/library/dd997415(v=vs.100).aspx
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
FireAndForget();
WaitOnTask();
}
private void FireAndForget()
{
Task t1 = Task.Factory.StartNew(() =>
{
Thread.Sleep(3000);
throw new Exception("boo");
});
Task c1 = t1.ContinueWith((t) =>
{
// The app global exception handler will not catch this.
}, TaskContinuationOptions.OnlyOnFaulted);
//MessageBox.Show("Task is running");
}
private void WaitOnTask()
{
Task t1 = Task.Factory.StartNew(() =>
{
throw new Exception("boo");
});
try
{
t1.Wait();
}
catch (Exception ex)
{
// The app global exception handler will catch this:
throw new Exception("Task", ex);
}
}
}
public partial class App : Application
{
public App()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.Current.DispatcherUnhandledException += new System.Windows.Threading.DispatcherUnhandledExceptionEventHandler(Current_DispatcherUnhandledException);
//System.Threading.Tasks.TaskScheduler.UnobservedTaskException += new EventHandler<System.Threading.Tasks.UnobservedTaskExceptionEventArgs>(TaskScheduler_UnobservedTaskException);
}
void TaskScheduler_UnobservedTaskException(object sender, System.Threading.Tasks.UnobservedTaskExceptionEventArgs e)
{
LogException(e.Exception);
}
void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
LogException(e.Exception);
}
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
LogException(e.ExceptionObject as Exception);
}
private void LogException(Exception ex)
{
// log it
string error = "This app has encountered an unexpected error . The error message is:" + Environment.NewLine + ex.Message + Environment.NewLine;
Exception tmp = ex.InnerException;
while (tmp != null)
{
error += "Inner exception is: " + Environment.NewLine + tmp.Message + Environment.NewLine;
tmp = tmp.InnerException;
}
error += "Please press OK to exit.";
MessageBox.Show(error, "Error");
Environment.Exit(-1);
}
}
사용하면StartNew
또는ContinueWith
, 모든 예외는 반환 된Task
.
마샬링 예외에는 두 가지 문제가 있습니다.
Task.Exception
귀하의 예외를AggregateException
.첫 번째 문제의 경우 일부 사용자는Flatten
또는Handle
직접 일할 회원AggregateException
. 나는 예외 처리를 언 래핑하는 것을 선호한다.Task.Exception.InnerException
대신에Task.Exception
.
두 번째 문제의 경우 일부 사람들은 다른 예외에서이를 감싸서 해결하지만 다른 대안을 택했습니다. .NET 4.5 도입ExceptionDispatchInfo
, 이는옳은이것을하는 방법. .NET 4.0에서는 다음과 같이 해킹 할 수 있습니다.
public static Exception Rethrow(this Exception ex)
{
typeof(Exception).GetMethod("PrepForRemoting",
BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(ex, new object[0]);
throw ex;
}
내가 여기서 뭔가를 놓치고 있는지 잘 모르겠지만, ContinueWith의 두 번째 매개 변수로 TaskScheduler.FromCurrentSynchronizationContext () UX 스레드에 마샬링됩니다.
좀 더 샘플을 원한다면 실제로 블로그 게시물을 썼습니다.http://www.briankeating.net/post/Why-I-love-the-Task-library
, KR 브라이언.
TaskScheduler.UnobservedTaskException
대신에Dispatcher.UnhandledException
- ghord
이 질문에 대한 답은 다음에서 찾을 수 있습니다.http://blogs.msdn.com/b/pfxteam/archive/2009/05/31/9674669.aspx
기본적으로 두 가지 시나리오가 있습니다. 즉, 작업을 기다릴 수있는 상황과 화재 나 잊을 수없는 상황이 있습니다. 작업을 기다릴 수있는 상황에서 질문에 표시된대로 try 블록에 랩핑하고 오류를 다시 제기하십시오. 글로벌 앱 핸들러가이를 잡아낼 것입니다.
작업을 기다릴 수없는 곳에서는 수동으로 로거에 전화해야합니다. 오류를 잡아낼 응용 프로그램 수준 처리기가 없습니다. TaskScheduler.UnobservedTaskException이 발생할 가능성이 있습니다. 그러나 이벤트는 매우 상황이 좋고 깨지기 쉽고 좋은 옵션이 아닙니다.
코드에서 예외를 전달하려면Wait
모든 작업에. 귀하가 다음과 같이 변경하면FireAndForget
방법Exception
중첩 된Task
호출 스레드로 다시 전달됩니다.
private void FireAndForget()
{
var tasks = new Task[2];
tasks[0] = Task.Factory.StartNew(() =>
{
Thread.Sleep(3000);
throw new Exception("boo");
});
tasks[1] = tasks[0].ContinueWith((t) =>
{
throw new Exception("nested boo", tasks[0].Exception);
}, TaskContinuationOptions.OnlyOnFaulted);
try
{
Task.WaitAll(tasks);
}
catch (AggregateException ex)
{
throw new Exception("Task", ex);
}
}
물론 이것은 더 이상 "화재와 잊기"방법이 아닙니다. 작업을 기다리는 것이 바람직하지 않은 경우 계속 내에서 로그 파일에 기록해야합니다.
너는 할 수있다.await
태스크 코드로부터 예외를받는 태스크의 완료.
try{
await Task.Factory.StartNew(() => throw Exception("hello"));
}catch{
// will get exception here
}
async
/await
대신에ContinueWith
? - Stephen ClearyMicrosoft.Bcl.Async
? - Stephen Clearyasync
할 것이다정말앱을 간소화 할 수 있지만 몇 분 안에 답변을 게시 할 수 있습니다. - Stephen Cleary