ASP MVC4 使用 httpclient 等待
ASP MVC4 await with httpclient
我正在学习如何在 MVC 中使用任务,但我完全迷路了。我需要从选定的网页下载源代码,找到一个元素,获取它的值并 return 它。而已。
为此,我使用 HtmlAgilityPack 和 HttpClient 来获取网页。
发生的问题是什么都没有等待来自 httpClient 的响应,因此导致在任务仍在进行时响应生成已完成。 (异步模块或处理程序已完成,而异步操作仍未决。)
我在这里阅读了很多主题、codeproj 和一些博客,仍然不明白问题出在哪里。最常见的解释是关于异步方法中 void 的结果类型,但我找不到任何其他方法来 return 等待值,而不是这个:
public float ReadPrice(Uri url)
{
switch (url.Host)
{
case "www.host1.xy":
return ParseXYZAsync(url).Result;
default:
return float.Parse("99999,99");
}
}
private Task<float> ParseXYZAsync(Uri url)
{
loadPage(url);
var priceNode = document.DocumentNode.SelectSingleNode(
@"//*[@id='pageWrapper']/div[4]/section[1]/div[4]/div[1]/div[1]/span");
var price = priceNode.InnerText;
...
return priceInFloat;
}
private async Task LoadPage(Uri url)
{
HttpClient http = new HttpClient();
var response = await http.GetByteArrayAsync(url);
String source = Encoding.GetEncoding("utf-8")
.GetString(response, 0, response.Length - 1);
source = WebUtility.HtmlDecode(source);
document.LoadHtml(source);
}
为了找出问题所在,您需要了解 async-await 的一个关键概念。当异步方法命中第一个 await
关键字时,控制权将返回给调用方法。这意味着当您这样做时:
loadPage(url);
该方法将同步 运行 直到它命中:
var response = await http.GetByteArrayAsync(url);
这会将控制权交还给 ParseWebSite
,这将继续执行并可能在异步操作实际完成之前结束。
你需要做的是使 LoadPage
return 成为 Task
和 await
完成:
private async Task<float> ParseWebsiteAsync(Uri url)
{
await LoadPageAsync(url);
var priceNode = document.DocumentNode.SelectSingleNode
(@"//*[@id='pageWrapper']/div[4]/section[1]/div[4]/div[1]/div[1]/span");
var price = priceNode.InnerText;
return priceInFloat;
}
private async Task LoadPageAsync(Uri url)
{
HttpClient http = new HttpClient();
var source = await http.GetAsStringAsync(url);
source = WebUtility.HtmlDecode(source);
document.LoadHtml(source);
}
旁注:
- 请遵循 .NET 命名约定。方法应该是 PascalCase 而不是 camelCase
- 请为异步方法添加 "Async" 后缀。例如,
LoadPage
应该变成 LoadPageAsync
.
private async void loadPage(Uri url) 需要 return 任务:
private async Task loadPage(Uri url)
那么你需要在调用方法中等待它:
private async Task<float> parseWEBSITEXY(Uri url)
{
await loadPage(url);
...
}
在您的代码加载页面中,它会立即 return。
还有一件事 - 不建议使用 async void,事件处理程序除外。始终 return 任务。
我正在学习如何在 MVC 中使用任务,但我完全迷路了。我需要从选定的网页下载源代码,找到一个元素,获取它的值并 return 它。而已。 为此,我使用 HtmlAgilityPack 和 HttpClient 来获取网页。 发生的问题是什么都没有等待来自 httpClient 的响应,因此导致在任务仍在进行时响应生成已完成。 (异步模块或处理程序已完成,而异步操作仍未决。)
我在这里阅读了很多主题、codeproj 和一些博客,仍然不明白问题出在哪里。最常见的解释是关于异步方法中 void 的结果类型,但我找不到任何其他方法来 return 等待值,而不是这个:
public float ReadPrice(Uri url)
{
switch (url.Host)
{
case "www.host1.xy":
return ParseXYZAsync(url).Result;
default:
return float.Parse("99999,99");
}
}
private Task<float> ParseXYZAsync(Uri url)
{
loadPage(url);
var priceNode = document.DocumentNode.SelectSingleNode(
@"//*[@id='pageWrapper']/div[4]/section[1]/div[4]/div[1]/div[1]/span");
var price = priceNode.InnerText;
...
return priceInFloat;
}
private async Task LoadPage(Uri url)
{
HttpClient http = new HttpClient();
var response = await http.GetByteArrayAsync(url);
String source = Encoding.GetEncoding("utf-8")
.GetString(response, 0, response.Length - 1);
source = WebUtility.HtmlDecode(source);
document.LoadHtml(source);
}
为了找出问题所在,您需要了解 async-await 的一个关键概念。当异步方法命中第一个 await
关键字时,控制权将返回给调用方法。这意味着当您这样做时:
loadPage(url);
该方法将同步 运行 直到它命中:
var response = await http.GetByteArrayAsync(url);
这会将控制权交还给 ParseWebSite
,这将继续执行并可能在异步操作实际完成之前结束。
你需要做的是使 LoadPage
return 成为 Task
和 await
完成:
private async Task<float> ParseWebsiteAsync(Uri url)
{
await LoadPageAsync(url);
var priceNode = document.DocumentNode.SelectSingleNode
(@"//*[@id='pageWrapper']/div[4]/section[1]/div[4]/div[1]/div[1]/span");
var price = priceNode.InnerText;
return priceInFloat;
}
private async Task LoadPageAsync(Uri url)
{
HttpClient http = new HttpClient();
var source = await http.GetAsStringAsync(url);
source = WebUtility.HtmlDecode(source);
document.LoadHtml(source);
}
旁注:
- 请遵循 .NET 命名约定。方法应该是 PascalCase 而不是 camelCase
- 请为异步方法添加 "Async" 后缀。例如,
LoadPage
应该变成LoadPageAsync
.
private async void loadPage(Uri url) 需要 return 任务:
private async Task loadPage(Uri url)
那么你需要在调用方法中等待它:
private async Task<float> parseWEBSITEXY(Uri url)
{
await loadPage(url);
...
}
在您的代码加载页面中,它会立即 return。 还有一件事 - 不建议使用 async void,事件处理程序除外。始终 return 任务。