ASP MVC4等待着httpclient

时间:2015-12-31 12:52:15

标签: c# asp.net-mvc-4 asynchronous async-await task-parallel-library

我正在学习如何在MVC中使用Tasks,我完全迷失了。我需要从选定的网页下载源代码,找到一个元素,获取其值并返回它。而已。 为此,我使用HtmlAgilityPack和HttpClient来获取网页。 发生的问题是没有任何东西等待来自httpClient的响应,从而导致在Task仍在进行时响应生成完成。 (在异步操作仍处于挂起状态时完成异步模块或处理程序。

我在这里阅读了很多主题,codeproj和一些博客,仍然不明白是什么问题。最常见的解释是关于异步方法中的结果类型的void,但我找不到任何其他方法来返回等待值,而不是:

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);
}

2 个答案:

答案 0 :(得分:4)

为了弄清楚你需要了解async-await的一个关键概念是什么?当异步方法命中第一个await关键字时,控制权将返回到调用方法。这意味着当你这样做时:

loadPage(url);

该方法将同步运行,直到它命中:

var response = await http.GetByteArrayAsync(url);

这将使控制权返回ParseWebSite,这将继续执行,并可能在异步操作实际完成之前结束。

您需要做的是让LoadPage返回Taskawait以完成它:

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);
}

旁注:

  1. 遵循.NET命名约定。方法应该是PascalCase而不是camelCase
  2. 添加&#34; Async&#34;异步方法的后缀。例如,LoadPage应该成为LoadPageAsync

答案 1 :(得分:1)

private async void loadPage(Uri url)需要返回一个Task:

private async Task loadPage(Uri url) 

然后你需要在调用方法中等待它:

private async Task<float> parseWEBSITEXY(Uri url)
{
 await loadPage(url);
...
}

在您的代码加载页面启动并立即返回。 还有一件事 - 除了事件处理程序之外,不建议使用async void。始终返回任务。