使用 HttpClient 但没有异步方法获取网站内容

Get the content of website using HttpClient but without async method

我正在尝试使用 `httpclinet 获取网站内容,您可以在此处看到

public async Task<List<NewsContent>> parsing(string newsArchive)
{
    List<NewsContent> lstResult=new List<NewsContent>();
    HttpClient http = new HttpClient();
    var response = await http.GetByteArrayAsync(newsArchive);
    String source = Encoding.GetEncoding("utf-8").GetString(response, 0, response.Length - 1);
    source = WebUtility.HtmlDecode(source);
    HtmlDocument resultat = new HtmlDocument();
    resultat.LoadHtml(source);

    List<HtmlNode> toftitle = resultat.DocumentNode.Descendants().Where
    (x => (x.Name == "div" && x.Attributes["class"] != null && x.Attributes["class"].Value.Contains("news_list"))).ToList();
    var li = toftitle[0].Descendants().Where
    (x => (x.Name == "div" && x.Attributes["class"] != null && x.Attributes["class"].Value=="news_item")).ToList();

    foreach (var item in li)
    {
        NewsContent newsContent = new NewsContent();
        newsContent.Url = item.Descendants("a").ToList()[0].GetAttributeValue("href", null);
        newsContent.Img = item.Descendants("img").ToList()[0].GetAttributeValue("src", null);
        newsContent.Title = item.Descendants("h2").ToList()[0].InnerText;

        //finding main news content
        var response1 = await http.GetByteArrayAsync("http://www.nsfund.ir/news" + newsContent.Url);
        String source1 = Encoding.GetEncoding("utf-8").GetString(response1, 0, response1.Length - 1);
        source1 = WebUtility.HtmlDecode(source1);
        HtmlDocument resultat1 = new HtmlDocument();
        resultat1.LoadHtml(source1);
        newsContent.Content = resultat1.DocumentNode.SelectSingleNode("//div[@class='news_content_container']").InnerText;


    }
    return  lstResult;
}

如您所见,我使用 async 方法获取数据。此处:

var response = await http.GetByteArrayAsync(newsArchive);

但问题是当我调用 async 函数时:

News newagent = new News();
Task<List<NewsContent>> lst = newagent.parsing("http://www.nsfund.ir");
Task.WaitAll(lst);
List<NewsContent> enresult = lst.Result;

我没有得到任何 result.so 我决定将这个 async 函数转换为普通函数,应该用这个替换什么样的代码:

var response = await http.GetByteArrayAsync(newsArchive);

我想我发现了你的代码的问题。
您没有将 NewsContent 对象添加到 List

foreach循环中请将其添加到List

lstResult.Add(newsContent)

希望它能解决您的 async 策略

的问题

But the problem is when i call my async function :

Task.WaitAll(lst);
List<NewsContent> enresult = lst.Result;

是的,这是个问题,好吧。实际上有两个问题:Task.WaitAllResult。它们都应替换为单个 await:

List<NewsContent> enresult = await lst;

核心问题是deadlock scenario,我在我的博客上有完整的解释。总之,await 将捕获当前上下文并使用它来恢复 async 方法。但是 ASP.NET 一次只允许一个线程在其请求上下文中。所以当 parsing 第一次被调用时,它会一直执行到它到达它的 await,然后是 returns。然后调用方法阻塞;这就是问题所在,因为通过阻塞,调用方法在 ASP.NET 请求上下文中保留了一个线程。

稍后,当 parsing 中的 await 完成后,它会尝试在那个 ASP.NET 请求上下文中恢复 parsing 方法,但它不能,因为有一个线程卡在该上下文中并且 ASP.NET 一次只允许一个线程。调用方法正在等待 parsing 完成,并且 parsing 正在等待上下文空闲。经典死锁。