簡體   English   中英

使用async / await和Task.Run時,不會顯示特定的異常

[英]Specific exceptions are not shown when using async/await and Task.Run

我有一個包含食譜列表的網頁。 在我的代碼中,我遍歷頁面並下載每個配方。 這是我正在做的偽代碼:

//This is the Recipe class
//The constructor accepts a link to the recipe
//This method scrapes the recipe
public Task ScrapeAsync(){
    return Task.Run(async () => {
        string WebPage;
        WebRequest request = WebRequest.Create(link);
        request.Method = "GET";
        using (WebResponse response = await request.GetResponseAsync())
        using (StreamReader reader = new StreamReader(response.GetResponseStream())) {
            WebPage = await reader.ReadToEndAsync();
        }
        //Non - async code here which is used to scrape the webpage
    }
}

我使用了Task.Run,​​因為Method中有異步和阻塞代碼。

//This is the RecipePage class
//This method scrapes the page
public Task GetRecipeListAsync(){
    return Task.Run(async () => {
        //I get the page using WebRequest and WebResponse in the same way as above

        //Non - async/blocking code here which scrapes the page and finds links to recipes. I do await Recipe.ScrapeAsync() somewhere here.
        //And I add the recipe objects to a public list in this class
    }
}

在表單中,它循環遍歷頁面列表,並await RecipePage.GetRecipeList()和其他東西。
這是for循環的位置:

private async void go_Click(object sender, EventArgs e){
    for (int i = (int)startingPageNUD.Value; i <= (int)finishingPageNUD.Value; ++i) {
        RecipePage page = new RecipePage(page + i);
        await page.GetRecipeListAsync();
        //Some other code here
    }
}

我的問題是,只要ScrapeAsync方法中發生異常,Visual Studio 2013就會指向Application.Run(new Form1())

static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

並告訴我Reflection.TargetInvocationException已經發生。 它沒有在我的代碼中顯示實際的異常。 例如,如果我在代碼中得到NullReferenceException ,則不會顯示。 因此,我必須編寫異步和非異步代碼,並使用非異步代碼進行調試。 有什么方法可以解決這個問題嗎?
我也有另一個問題。 我是否以正確的方式使用async / await和Task?

我是否以正確的方式使用async / await和Task?

很接近了。 我認為在這種情況下不需要Task.Run (它應該僅用於從UI線程中Task.Run CPU密集型操作,並且HTML抓取通常足夠快以保持在UI上而沒有任何不利影響)。

我提出的另一個建議是讓async Task方法盡可能多地返回值,而不是將成員變量修改為副作用。 在您的情況下,考慮讓ScrapeAsync返回自己的列表而不是更新共享列表,並讓調用代碼執行列表合並。

關於您的異常, TargetInvocationException將具有包含詳細信息的InnerException async void事件處理程序中的異常管理實際上與常規void事件處理程序中的異常相同:如果一個轉義事件處理程序,則轉到應用程序主循環。 如果你不想這樣,你就必須抓住它(對於同步和異步處理程序)。

將getRecipeList代碼封裝在try / catch中。

在catch代碼中,獲取異常消息和堆棧跟蹤並將它們分配給Recipe類的變量,當操作完成時,您將在主線程中測試/顯示它們。

private string TheException = "" ;

public Task GetRecipeListAsync()
{
  TheException = "" ;
  Task result = Task.Run(async () => 
  {
    try 
    {  
      //I get the page using WebRequest and WebResponse in the same way as above
      ...
     }
     catch (Exception Ex)  
  }
  if (TheException!="") MessageBox.show(TheException) ; 
  // or Throw an exception with
  return result ; 
}

您也可以在GoClick過程中測試“TheExceptio”。

好的。 感謝您的編輯,我現在可以回答。

你的問題是這個功能:

private async void go_Click(object sender, EventArgs e){
    for (int i = (int)startingPageNUD.Value; i <= (int)finishingPageNUD.Value; ++i) {
        RecipePage page = new RecipePage(page + i);
        await page.GetRecipeListAsync();
        //Some other code here
    }
}

問題是該函數一旦到達await就會返回到它所調用的內容。 現在如果page.GetRecipeListAsync(); 拋出異常,這個異常會在continuation handler中拋出。 此處理程序在UI的任務隊列中執行。 拋出異常會導致UI的任務循環崩潰,這會產生各種有趣的影響,包括奇怪的異常。

async void函數中,您應該始終通過將所有代碼包裝到try ... catch來處理任何傳入的異常。 如果您發現異常,則崩潰應用程序是否由您決定。

事情的工作一般的做法是拋出內部的任何異常Task ,並通過在擴展async功能被再次拋出await async void函數不會await任何地方await ,所以這不起作用。

關於async的用法。 我不認為你需要將每個函數包裝到一個Task但你可以這樣做。 通常你不需要像這樣強迫它進入背景。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM