我有一个包含食谱列表的网页。在我的代码中,我循环浏览页面并下载每个食谱。这是我正在做的伪代码:
//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 是因为方法中同时包含异步代码和阻塞代码。
//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?
最佳答案
Am I using async/await and Task in the correct way?
非常接近。我认为在这种情况下不需要 Task.Run
(它应该只用于将 CPU 密集型操作移出 UI 线程,并且 HTML 抓取通常足够快以留在 UI 上没有任何不良影响)。
我要提出的另一个建议是让 async Task
方法尽可能返回 值,而不是修改成员变量作为副作用。在您的情况下,考虑让 ScrapeAsync
返回其自己的列表而不是更新共享列表,并让调用代码执行列表合并。
关于您的异常,TargetInvocationException
将有一个包含详细信息的 InnerException
。 async void
事件处理程序中的异常实际上与常规 void
事件处理程序中的异常管理方式相同:如果一个事件处理程序转义,那么它会进入应用程序主循环.如果您不想要它,则必须捕获它(对于同步和异步处理程序)。
关于c# - 使用 async/await 和 Task.Run 时不显示特定异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31340712/