[英]How to catch exception thrown in a task in a task
我需要帮助捕获 C# 中的异常。我有一个 Windows 服务,它充当其他模块的包装器,因此为了没有多个 Windows 服务,我启动所有模块/代理,这就是我们在该包装器 Windows 服务中调用它们的方式。 每个“代理”都在自己的任务中启动。 我无法控制代理本身在做什么,所以它可以而且会不时地启动一个任务或线程,如果抛出异常,我将无法捕获它。 我尝试了不同的事情,但无法做到。 因此,如果在生产中发生此类异常,我的整个服务以及所有代理都会崩溃,这是一场噩梦。 我尝试用一个示例代码来简化它:
public class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
AppDomain.CurrentDomain.UnhandledException += (o, e) =>
{
Console.WriteLine("CurrentDomain Unhandled Exception: {0}", e.ExceptionObject);
};
TaskScheduler.UnobservedTaskException += (s, e) =>
{
Console.WriteLine("TaskScheduler.UnobservedTaskException Unhandled Exception: {0}", e.Exception);
e.SetObserved();
};
Task.Factory.StartNew(() =>
{
Task.Factory.StartNew(() => throw new Exception("I am a exception ! Catch me !"));
}, TaskCreationOptions.LongRunning)
.ContinueWith((t) =>
t.Exception.InnerExceptions.ToList().ForEach(e => Console.WriteLine("Error executing task.{0}", e)),
TaskContinuationOptions.OnlyOnFaulted);
Console.WriteLine("If you read this, application is not crashed!");
Console.ReadKey();
Task.Factory.StartNew(() =>
{
throw new Exception("I am a exception ! Catch me !");
});
}
}
那么如何捕获异常呢? 它不会被我的任何处理程序获取。
重要的是我对那部分代码没有影响,那是我的“代理人”:
Task.Factory.StartNew(() => throw new Exception("I am a exception ! Catch me !"));
其他一切我都可以改变。
编辑:不幸的是,提供的解决方案似乎对我不起作用。 我仍然无法捕获发生的异常。 当我展示我的原始代码时,它可能会变得更加清晰:
private async Task StartAgent(IAgent agent)
{
_logger.LogInfo("Agent starting with instanceId {0}", agent.GetInstanceGuid());
if (agent == null)
{
throw new ArgumentNullException("agent");
}
try
{
Task task = await Task.Factory.StartNew(async () =>
{
agent.Start();
}, TaskCreationOptions.LongRunning);
await task.ContinueWith((t) =>
{
var aggException = t.Exception.Flatten();
foreach (var exception in aggException.InnerExceptions)
_logger.LogError("Error executing agent task.{0}", exception, t.Id);
}, TaskContinuationOptions.OnlyOnFaulted);
_agents[agent.GetInstanceGuid()].Task = task;
_agents[agent.GetInstanceGuid()].LastTaskStatus = task.Status;
}
catch (Exception e)
{
_logger.LogError("Exception in Agent Task.",e);
}
}
所以 agent.Start() 是我在任务中调用的,我不知道里面发生的一切。 代理可以创建任务,线程他想要的一切。 Start() 也是无效的,我无法更改界面来等待它。
[Task.Factory.StartNew] 包装在一个 void 方法中。
那么,代码故意忽略所有异常。 这种“即发即弃”之所以有问题,正是因为它忽略了返回的任务。 所有异常都放在该任务上,然后被忽略。
TaskScheduler.UnobservedTaskException
捕获它
UnobservedTaskException
或AppDomain.FirstChanceException
是您唯一的实际选择。 这些都不是特别好(即,它们是全局处理程序),但它们是您唯一的选择,因为您控制之外的代码明确忽略了异常。
感谢所有的答案。 我现在找到了一个适合我的简单解决方案。 我所要做的就是在我的 app.config 的“运行时”部分添加这个标志
<legacyUnhandledExceptionPolicy enabled="1" />
就像这里描述的那样: How to prevent an exception in a background thread from terminating an application?
我遇到了问题,即使我能够捕捉到我的异常,我的服务仍然会在之后停止。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.