簡體   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