2012-12-31 58 views
2

內例外,我有這樣的代碼:捕獲一個異步委託

public async Task AsyncMethod() 
    { 
     await Task.Factory.StartNew(() => 
     { 
      throw new Exception(); 
     }); 
    } 

    public ActionResult Index() 
    { 
     var t1 = Task.Factory.StartNew(() => { throw new Exception(); }); 
     var t2 = Task.Factory.StartNew(() => { throw new Exception();}); 
     var t3 = Task.Factory.StartNew(async() => { await AsyncMethod(); }); 

     try 
     { 
      Task.WaitAll(t1, t2, t3); 
     } 
     catch (AggregateException ex) 
     { 
      var count1 = ex.InnerExceptions.Count; 
      var count2 = ex.Flatten().InnerExceptions.Count; 

      throw; 
     } 

     return View(); 
    } 

我想明白爲什麼COUNT1 COUNT2和變量是2,而不是3,我怎麼能進去AsyncMethod第三個例外呢?

回答

3

我想了解爲什麼count1和count2變量是2而不是3,我如何得到AsyncMethod中的第三個異常?

Task.Factory.StartNew返回一個基本的Task。如果您通過async代表,則返回的Task僅代表async方法的開始(直到其發送給它的點)。

您應該使用Task.Runasync的代碼。 Task.Run將爲async代表創建Task包裝,因此從Task.Run返回的Task代表整個async方法。

Stephen Toub有an excellent blog post detailing the differences between Task.Run and Task.Factory.StartNew

另外,正如usr提到的,只要您在GUI或ASP.NET上下文中阻止Task而不是await,就會遇到死鎖問題。我有a blog post that goes into detail about this deadlock problem。您應該使用await Task.WhenAll而不是Task.WaitAll

所以,這裏是你的代碼同時適用變化:

public async Task AsyncMethod() 
{ 
    await Task.Run(() => 
    { 
     throw new Exception(); 
    }); 
} 

public async Task<ActionResult> Index() 
{ 
    var t1 = Task.Run(() => { throw new Exception(); }); 
    var t2 = Task.Run(() => { throw new Exception();}); 
    var t3 = Task.Run(async() => { await AsyncMethod(); }); 

    try 
    { 
     await Task.WhenAll(t1, t2, t3); 
    } 
    catch (Exception) 
    { 
     var ex1 = t1.Exception.InnerException; 
     var ex2 = t2.Exception.InnerException; 
     var ex3 = t3.Exception.InnerException; 

     throw; 
    } 

    return View(); 
} 
+0

你的回答比我的完整。我建議它被接受。 – usr

+0

我試過你的代碼版本,但它沒有打到AggregateException的catch,因爲'await Task.WhenAll'這行引發了一個System.Exception與.Message'類型'System.Exception'的異常被拋出。 – MuriloKunze

+0

@MuriloKunze:你是對的。我更新了代碼以顯示用'WhenAll'處理異常的另一種方法。 –

3

更改此

var t3 = Task.Factory.StartNew(async() => { await AsyncMethod(); }); 

這樣:

var t3 = AsyncMethod(); 

您已經的任務。無需通過在線程池中執行來包裝它。

通過包裝它,您可以將您已經擁有(並且最終會發生故障)的Task轉換爲從不發生故障的Task<Task>(僅限其Task.Result故障)。當然,WaitAll在外部任務上運行,所以它從不會看到異常。

用調試器遍歷這些代碼來檢查所有變量的運行時值是一種很好的技術。注意這個錯誤比通過查看代碼要容易得多(「看起來」對我來說足夠了,因爲我有這方面的經驗 - 但是如果我沒有經驗,我將需要運行此代碼並進行調試它)。

+0

我改變了它,但現在漁獲不起作用。如果我也刪除了AsyncMethod內部的等待,那麼這個catch就可以工作,但結果是兩個。 – MuriloKunze

+0

你有一個不相關的錯誤:你正在等待導致ASP.NET中出現死鎖的任務。等待它(Task.WaitAll => awit Task.WhenAny),它會工作。你也可以研究爲什麼在ASP.NET和WinForms中等待任務是一個壞主意。 – usr

+0

你沒有抓住這個的部分原因是你使用'var'。如果你必須輸入變量的類型,那麼顯然這不是一項任務,而是一項任務。 – Servy