2017-09-29 103 views
2

關於:AsyncContextThreadAsyncContext - > AsyncContextThread處理異常

https://github.com/StephenCleary/AsyncEx/wiki/AsyncContext

https://github.com/StephenCleary/AsyncEx/blob/master/src/Nito.AsyncEx.Context/AsyncContextThread.cs

它真不是蓋的如何處理捕獲當線程開始發生的異常。

public partial class MyService : ServiceBase 
{ 
    private readonly AsyncContextThread _thread = new AsyncContextThread(); 

    private readonly CancellationTokenSource _cts = new CancellationTokenSource(); 

    public MyService() 
    { 
     InitializeComponent(); 
    } 

    public void Start() 
    { 
     OnStart(null); 
    }  

    protected override void OnStart(string[] args) 
    { 
     try 
     {  
      _thread.Factory.Run(StartAsync); 
     } 
     catch (Exception ex) 
     {     
      // Exception? 
     } 
    } 

    private async Task StartAsync() 
    { 
     throw new Exception("things went wrong"); 
    } 

    protected override void OnStop() 
    { 
     if (!_cts.IsCancellationRequested) 
      _cts.Cancel(); 
     _thread.JoinAsync().GetAwaiter().GetResult(); 
    } 
} 

我似乎沒有趕上在catch{}塊東西,除了我嘗試添加這些對我的Program.cs(主入口點)。

TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; 
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; 

但是在上面的代碼中沒有觸發事件處理程序方法。

Q)在這種情況下你如何正確處理異常?

作爲一個方面說明,我相當確定以前使用AsyncContext並在Visual Studio中進行調試確實發現了異常,所以我不確定是否有某種同步。上下文我很想念,當試圖添加異常處理程序。

編輯

我知道我可以在StartAsync方法中try/catch,但我在獲得關鍵是能夠捕捉任何未處理的異常,並確保我可以登錄他們。

+0

我拼命希望斯蒂芬Cleary回答這個問題:) – peteski

+1

我認爲你需要'等待''try'中的方法來捕獲異常。目前異步方法將立即返回給調用者,拋出的錯誤將丟失。 – Equalsk

+0

@Equalsk你不能在Windows服務的OnStart方法中「等待」任何東西,因爲它是一個覆蓋,並且必須匹配預期的簽名。 AsyncContext/AsyncContextThread的整個想法(據我所知)是允許你從不允許的地方啓動異步方法(即控制檯應用程序或Windows服務)。 – peteski

回答

2

我一直做異步的Win32服務......現在幾年一篇博客文章... :)

它真不是蓋的如何處理捕獲例外線程啓動時發生。

AsyncContextThread實際上在創建後立即啓動。你在做什麼OnStart是排隊工作的上下文。

對這項工作的例外是在從Run返回Task觀察,並觀察它適當的方法是使用await

protected override async void OnStart(string[] args) 
{ 
    try 
    {  
     await _thread.Factory.Run(StartAsync); 
    } 
    catch (Exception ex) 
    {     
     // Exception! 
    } 
} 

的幾個注意事項:

通常情況下,你應該avoid async void。該規則的例外是事件處理程序或類似事件的方法(如OnStart)。當你使用async void,你應該考慮有一個try/catch圍繞整個async void方法體(我們這樣做)。

await is superior to ContinueWith。在這種特殊情況下,ContinueWith可以正常工作,但在一般情況下,這是不可取的:它不理解async代表,它不使用適當的默認TaskScheduler,它不使用適當的默認延續標誌。這些都是await只是爲你處理。

+0

感謝Stephen的回覆,只是跟進,我有'public void Start()'方法在Visual Studio中調試時運行,我應該試着獲取awaiter和它的結果,或者只是把它作爲service.Start();? – peteski

+1

我想你必須使用'Start()'。由於它不返回任務,因此無法阻止它。 –

3

您可以使用Continuation來處理異常。

protected override void OnStart(string[] args) 
{ 
    _thread.Factory.Run(StartAsync).ContinueWith(t => 
    { 
     var aggregate = t.Exception.Flatten(); 
     foreach(var exception in aggregate.InnerExceptions) 
     { 
      // Handle exception 
     } 
    }, TaskContinuationOptions.OnlyOnFaulted); 
} 
+0

我明白什麼你在說,我認爲我希望得到Stephen關於這個問題的意見的原因是他的書「C#Cookbook中的併發」(第35/36頁)討論了在異步void類型方法中處理異常。給出的代碼示例並沒有使用延續,而是使用了代碼示例中的try/catch,因此這看起來不正確。 – peteski