任务吞下抛出的异常
Task swallows the exception thrown
在下面的方法中,当在 TRY 块中抛出异常时,它正在被吞噬。我怎样才能让它抛出异常,以便它被写入以登录 catch 块?日志编写器工作正常。谢谢!
public static bool MonitorQueueEmptyTask(string queueName, CancellationTokenSource tokenSource)
{
try
{
Task<bool> task = Task.Factory.StartNew<bool>(() =>
{
while (!QueueManager.IsQueueEmpty(queueName))
{
if (tokenSource.IsCancellationRequested)
{
break;
}
Thread.Sleep(5000);
throw new Exception("Throwing an error!"); //THIS THROW IS SWALLOWED -- NO LOG WRITTEN ON CATCH
};
return true;
}, tokenSource.Token);
}
catch (Exception ex)
{
WriteExceptionToLog(ex.Stack); //it's not that this method doesn't work. it works fine.
return false;
}
return true;
}
异常没有被吞噬;只是它不会发生在执行 try/catch 块的线程上,而是发生在单独的任务线程上。
如果你没有观察到任务的结果或异常,当任务最终被垃圾回收时,它会抛出一个异常,说任务没有被观察到。除非你通过处理 TaskScheduler.UnobservedTaskException
来捕获它,否则它会使进程崩溃。
如果您想即刻忘记,可以使用 ContinueWith
附加延续。当前的 try-catch
根本帮不了你,因为异常封装在 Task
中。如果这是 "fire and forget",那么您可以记录异常:
public static Task MonitorQueueEmptyTask(
string queueName, CancellationTokenSource tokenSource)
{
return Task.Factory.StartNew<bool>(() =>
{
while (!QueueManager.IsQueueEmpty(queueName))
{
if (tokenSource.IsCancellationRequested)
{
break;
}
Thread.Sleep(5000);
throw new Exception("Throwing an error!");
};
}, tokenSource.Token, TaskCreationOptions.LongRunning).ContinueWith(faultedTask =>
{
WriteExceptionToLog(faultedTask.Exception);
}, TaskContinuationOptions.OnlyOnFaulted);
}
反过来,这不会在抛出异常后传播异常,但会提供一种记录错误的机制。如果您希望异常得到妥善处理,可以注册到TaskScheduler.UnobservedTaskException
。此外,如果您希望未处理的异常终止您的应用程序,您可以在配置中设置 ThrowUnobservedTaskExceptions enabled="true"
。 ContinueWith
将在您查看 task.Exception
属性.
时考虑异常 "handled"
我也有这个问题,我真的不喜欢 App.config 的整个想法,所以可以提供另一种解决方案来防止异常消失:)
保存异常然后在 Task.Run 完成后抛出它,例如
private async void Function() {
Exception save_exception = null;
await Task.Run(() => {
try {
// Do Stuff
} catch (Exception ex) {
save_exception = ex;
}
}).ContinueWith(new Action<Task>(task => {
if (save_exception != null)
throw save_exception;
// Do Stuff
}));
}
在下面的方法中,当在 TRY 块中抛出异常时,它正在被吞噬。我怎样才能让它抛出异常,以便它被写入以登录 catch 块?日志编写器工作正常。谢谢!
public static bool MonitorQueueEmptyTask(string queueName, CancellationTokenSource tokenSource)
{
try
{
Task<bool> task = Task.Factory.StartNew<bool>(() =>
{
while (!QueueManager.IsQueueEmpty(queueName))
{
if (tokenSource.IsCancellationRequested)
{
break;
}
Thread.Sleep(5000);
throw new Exception("Throwing an error!"); //THIS THROW IS SWALLOWED -- NO LOG WRITTEN ON CATCH
};
return true;
}, tokenSource.Token);
}
catch (Exception ex)
{
WriteExceptionToLog(ex.Stack); //it's not that this method doesn't work. it works fine.
return false;
}
return true;
}
异常没有被吞噬;只是它不会发生在执行 try/catch 块的线程上,而是发生在单独的任务线程上。
如果你没有观察到任务的结果或异常,当任务最终被垃圾回收时,它会抛出一个异常,说任务没有被观察到。除非你通过处理 TaskScheduler.UnobservedTaskException
来捕获它,否则它会使进程崩溃。
如果您想即刻忘记,可以使用 ContinueWith
附加延续。当前的 try-catch
根本帮不了你,因为异常封装在 Task
中。如果这是 "fire and forget",那么您可以记录异常:
public static Task MonitorQueueEmptyTask(
string queueName, CancellationTokenSource tokenSource)
{
return Task.Factory.StartNew<bool>(() =>
{
while (!QueueManager.IsQueueEmpty(queueName))
{
if (tokenSource.IsCancellationRequested)
{
break;
}
Thread.Sleep(5000);
throw new Exception("Throwing an error!");
};
}, tokenSource.Token, TaskCreationOptions.LongRunning).ContinueWith(faultedTask =>
{
WriteExceptionToLog(faultedTask.Exception);
}, TaskContinuationOptions.OnlyOnFaulted);
}
反过来,这不会在抛出异常后传播异常,但会提供一种记录错误的机制。如果您希望异常得到妥善处理,可以注册到TaskScheduler.UnobservedTaskException
。此外,如果您希望未处理的异常终止您的应用程序,您可以在配置中设置 ThrowUnobservedTaskExceptions enabled="true"
。 ContinueWith
将在您查看 task.Exception
属性.
我也有这个问题,我真的不喜欢 App.config 的整个想法,所以可以提供另一种解决方案来防止异常消失:)
保存异常然后在 Task.Run 完成后抛出它,例如
private async void Function() {
Exception save_exception = null;
await Task.Run(() => {
try {
// Do Stuff
} catch (Exception ex) {
save_exception = ex;
}
}).ContinueWith(new Action<Task>(task => {
if (save_exception != null)
throw save_exception;
// Do Stuff
}));
}