2013-10-16 98 views
0

我正在通過使用async/await模式來處理異常處理(似乎是如此)非常着名的問題。具體而言,我的上下文位於HTTP客戶端上,但我也嘗試過更簡單的測試,並且其行爲相同。異步/等待和WebException處理

考慮下面的程序,這是我的原始應用程序的上下文的超簡化版本。


class Program 
{ 
    static void Main(string[] args) 
    { 
     Test(); 

     Console.Write("Press any key..."); 
     Console.ReadKey(); 
     Console.WriteLine(); 
    } 


    static async void Test() 
    { 
     var c = new MyClient(); 

     try 
     { 
      var uri = new Uri("http://www.google.com/"); //valid address 
      var s = await c.GetString(uri); 
      Console.WriteLine(s.Length); 
     } 
     catch (WebException ex) 
     { 
      Console.WriteLine(ex.Message); 
     } 

     try 
     { 
      var uri = new Uri("http://www.foo.bah/"); //non-existent address 
      var s = await c.GetString(uri); 
      Console.WriteLine(s.Length); 
     } 
     catch (WebException ex) 
     { 
      Console.WriteLine(ex.Message); 
     } 
    } 
} 


class MyClient 
{ 
    public async Task<string> GetString(Uri uri) 
    { 
     var client = new HttpClient(); 
     return await client.GetStringAsync(uri); 
    } 
} 

當程序啓動時,它將第一個網站的頁面下載爲一個字符串,然後顯示其長度:沒關係。之後,當對一個無效地址執行相同的操作時,客戶端引發一個WebException(這正是我想要的),但它沒有被捕獲。

更新:作爲「未捕獲」,我的意思是代碼實際上不會流經「catch」分支並以靜默方式顯示異常消息。相反,VS IDE顯示異常,調試中斷。

任何體面的解決方案來捕捉異常?

非常感謝提前。

+0

目前您提供甚至不會編譯代碼 - 你必須申報'MyClient.GetString'返回任務''代替Task'的'。你也沒有告訴我們究竟發生了什麼。 –

+1

也許你已經將調試器設置爲「打破所有異常」,並且只是認爲它沒有被捕獲? – usr

+0

可能的解決方案:註冊域並在其上放置一些網站。 – usr

回答

1

雖然您已經發現例外是HttpRequestException而不是WebException,但我仍想強調一些關於異步等待操作符用法的重要信息。

  1. async void的類型是火&忘記的,僅&只對事件處理程序。
  2. 只要編譯器達到第一個await運算符內部異步方法控制返回給調用者。

調試代碼: -

由於您使用異步虛空中的測試方法,以便控制返回給調用者和執行直到該行Console.Write("Press any key...");無需有關任務的任何信息,然後你正在等待用戶輸入。 同時,來自等待方法的響應來自Test方法內部的執行。

如果您在main()內部註釋掉Console.ReadKey();行,或者用戶立即提供輸入,那麼您會注意到響應可能打印,也可能不打印。這是因爲你沒有等待執行的任務,你只需信任用戶,直到任務完成後他纔會輸入任何內容。

解決方案: -

解決方案是從測試(返回任務),然後等待,直到它完成,下面是更新的代碼還需要說明的方法名的末尾添加異步被命名約定必須遵循的讓您免於區分異步和同步方法的麻煩。

class Program 
{ 
    static void Main(string[] args) 
    { 
     Task task = TestAsync(); 

     Console.Write("Press any key..."); 
     task.wait(); 
     //Console.ReadKey(); 
     Console.WriteLine(); 
    } 


    static async Task<string> TestAsync() 
    { 
     var c = new MyClient(); 

     try 
     { 
      var uri = new Uri("http://www.google.com/"); //valid address 
      var s = await c.GetStringAsync(uri); 
      Console.WriteLine(s.Length); 
     } 
     catch (HttpRequestException ex) 
     { 
      Console.WriteLine(ex.Message); 
     } 

     try 
     { 
      var uri = new Uri("http://www.foo.bah/"); //non-existent address 
      var s = await c.GetStringAsync(uri); 
      Console.WriteLine(s.Length); 
     } 
     catch (HttpRequestException ex) 
     { 
      Console.WriteLine(ex.Message); 
     } 
     //to avoid compiler error 
     return null; 
    } 
} 


class MyClient 
{ 
    public async Task<string> GetStringAsync(Uri uri) 
    { 
     var client = new HttpClient(); 
     return await client.GetStringAsync(uri); 
    } 
} 
+0

我感謝你的解釋,但我的實際問題是沒有被「catch」條款捕獲的異常。無論如何,關於「空白」,我不介意ReadKey序列:我只想開始一個任務並顯示異常消息。最後,我注意到任務一直涉及輔助線程,所以這根本不是問題。 –

+0

我理解你的擔憂,但我只是覺得即使在你的虛擬代碼中也能正確使用異步等待,這可能會幫助其他人理解這些關鍵字。 :) –