使用 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.WaitAll
和 Result
。它们都应替换为单个 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
正在等待上下文空闲。经典死锁。
我正在尝试使用 `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.WaitAll
和 Result
。它们都应替换为单个 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
正在等待上下文空闲。经典死锁。