繁体   English   中英

如何在任务中捕获任务中抛出的异常

[英]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捕获它

UnobservedTaskExceptionAppDomain.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM