根据我的研究,我学到了以下内容:
TaskScheduler.UnobservedTaskException
必须等待该任务被垃圾收集,然后该任务的未被观察到的异常才会冒出UnobservedTaskException
事件。Task.Wait()
,那么它永远不会被调用,因为你正在阻止来自任务的即将发生的结果,因此异常将被抛出Task.Wait()
而不是泡沫直至UnobservedException
事件。GC.Collect()
通常是一个坏主意,除非您确切知道自己在做什么,因此在这种情况下确认事情很好,但不能作为问题的正确解决方案。问题
如果我的应用程序在垃圾收集器启动之前退出,我绝对100%无法触发我的UnobservedTaskException
事件。
请注意以下代码:
class Program
{
static void Main(string[] args)
{
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
Task.Factory.StartNew(() =>
{
Console.WriteLine("Task started.");
throw new Exception("Test Exception");
});
Thread.Sleep(1000);
//GC.Collect();
//GC.WaitForPendingFinalizers();
}
static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
File.WriteAllText(@"C:\data\TestException.txt", e.Exception.ToString());
Console.WriteLine("UNOBSERVED EXCEPTION");
}
}
没有写入异常文件,也没有任何内容写入控制台。在应用程序退出后10-15分钟甚至更长时间可以继续,但我仍然看不到我的应用程序的遗骸被垃圾收集的证据。您可能会问,为什么不在退出时收集?好吧,我真实的情况是我的异常陷阱在Windows服务中托管的WCF服务中运行。我无法在Windows服务关闭时陷阱(因此手动调用GC.Collect()
),因为就我所见,没有任何事件。
我哪里错了?我如何确保如果WCF服务内部的某些内容最终会破坏我的Windows服务,那么我有机会在服务崩溃之前记录异常?
答案 0 :(得分:7)
对我来说,TaskScheduler.UnobservedTaskException最初给出了非常错误的安全感。如果它依赖于垃圾收集,那真的不值得。
我发现以下解决方案取自this msdn article,更加可靠。它基本上只在task1中存在未处理的异常时执行延续块(在那里记录异常),并且不阻止UI执行。
您可能还想展平嵌套的AggregateExceptions,并可能创建一个扩展方法,如Reed Copsey depicted here。
var task1 = Task.Factory.StartNew(() =>
{
throw new MyCustomException("Task1 faulted.");
})
.ContinueWith((t) =>
{
Console.WriteLine("I have observed a {0}",
t.Exception.InnerException.GetType().Name);
},
TaskContinuationOptions.OnlyOnFaulted);
答案 1 :(得分:2)
森,
你的观点都是真的。请尝试以下方法:
namespace ConsoleApplication1
{
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
Task.Factory.StartNew(() =>
{
Console.WriteLine("Task started.");
throw new Exception("Test Exception");
});
Thread.Sleep(1000);
Console.WriteLine("First Collect");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Waiting");
Console.ReadKey();
}
static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
Console.WriteLine("UNOBSERVED EXCEPTION");
}
}
}
我注意到调试器经常“捕获”UnobservedTaskException事件,导致它无法正确触发。在调试器外部运行 ,每次关闭前都会打印“未观察到的异常”。