Récupère le contenu du site en utilisant HttpClient mais sans méthode asynchrone

asp.net-mvc asynchronous c# html-agility-pack http

Question

J'essaie de récupérer le contenu du site Web en utilisant `httpclinet comme vous pouvez le voir ici

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

Comme vous pouvez le voir, j’ai utilisé la méthode async pour obtenir les données. Ici:

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

Mais le problème est quand j'appelle ma fonction async :

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

Je n'ai aucun résultat. J'ai donc décidé de convertir cette fonction async en une fonction normale. Quel type de code devrait être remplacé par ceci:

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

Réponse acceptée

Je suppose que j'ai trouvé le problème avec votre code.
Vous NewsContent pas l'objet NewsContent à votre List .

dans la boucle foreach , ajoutez-le à la List

lstResult.Add(newsContent)

J'espère que cela résoudra le problème avec votre stratégie async


Réponse populaire

Mais le problème est quand j'appelle ma fonction asynchrone:

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

Oui, c'est un problème, d'accord. Deux problèmes, en fait: Task.WaitAll et Result . Ils devraient tous deux être remplacés par une seule await :

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

Le problème principal est un scénario d’impasse que j’explique en détail sur mon blog. En résumé, await capturera le contexte actuel et l’utilisera pour reprendre la méthode async . Mais ASP.NET n'autorise qu'un seul thread à la fois dans son contexte de requête. Ainsi, lorsque l' parsing est appelée pour la première fois, il s'exécute jusqu'à ce qu'il atteigne son await , puis il revient. La méthode d'appel se bloque alors; c'est là que réside le problème, car en bloquant, la méthode d'appel conserve un fil dans ce contexte de demande ASP.NET.

Plus tard, lorsque l' parsing await interne est terminée, il tente de reprendre la méthode d' parsing dans le contexte de la demande ASP.NET, mais il ne le peut pas, car un thread est bloqué dans ce contexte et ASP.NET n'autorise qu'un seul thread à la fois. La méthode d'appel attend que l' parsing terminée et l' parsing attend que le contexte soit libre. Impasse classique.




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi