0

I have the code below that uses HttpClient to download content for a series of websites. However, whilst a synchronous inner function works fine in the Parallel.ForEach, I have been unable to get the asychronous version to work.

I would appreciate to know how to resolve this and how the code should look.

The code is a simple console app. However, I have been unable to get this to work at all (synchronous or async) in a Windows Form app. Can anyone explain why this is so?

Code:

using DLWeb;
using System.Collections.Concurrent;
 
// initialize test data
ConcurrentBag<Website> _websites = [ new Website("BBC", "https://www.bbc.co.uk"),
                                     new Website("Google", "https://www.google.com"),
                                     new Website("Amazon","https://www.amazon.com")];
// set mode
bool USE_DOWNLOAD_ASYNC = true;

string mode = USE_DOWNLOAD_ASYNC ? "Asynchronously" : "Synchronously";
Console.WriteLine($"Starting (Running Download {mode})...{Environment.NewLine}");

ParallelLoopResult _loopRes = new();

if (USE_DOWNLOAD_ASYNC) // Async 
{
    await Task.Run(() =>
    {
        _loopRes = Parallel.ForEach<Website>(_websites, async (item) =>
        {
            var res = await DownloadAsync(item);
            item.Content = res;
        });
    });
}
else
{
    await Task.Run(() =>
    {
        _loopRes = Parallel.ForEach<Website>(_websites, (item) =>
        {
            string s = "";

            s = Download(item.URL);
            item.Content = s;
        });
    });
}

if (_loopRes.IsCompleted)
{
    foreach (var item in _websites)
    {
        Console.WriteLine($"{item.Name}: {item.Content.Length}{Environment.NewLine}");
    }

    Console.WriteLine("Done.");
}

Console.ReadKey();

// ----------------------------------------------------

static string Download(string site)
{
    HttpClient httpClient = new();

    var r = httpClient.GetStringAsync(site).Result;

    return r;
}

async static Task<string> DownloadAsync(Website item)
{
    HttpClient httpClient = new();
    string res;
    res = "" + await httpClient.GetStringAsync(item.URL);
    return res;
}

The Website class:

 public class Website
 {
     public string Name { get; set; } = "";
     public string URL { get; set; } = "";
     public string Content { get; set; } = "";

     public Website()
     {
     }

     public Website(string name, string url)
     {
         Name = name;
         URL = url;
     }
 } 

Any help appreciated.

11
  • 1
    The Parallel.ForEach is not async-friendly. Look at the .NET 6 Parallel.ForEachAsync. Commented Jan 26 at 17:08
  • @DMan please keep the question clean from meta-discussions. You can always use comments to explain what are the specifics that make this question different from the other similar questions, where people tried to use the Parallel.ForEach API with an async delegate, and didn't work as well as they expected. Commented Jan 27 at 14:12
  • @TheodorZoulias The other Stack Overflow questions do not answer that for which I am seeking answers, which is obviously not helpful. Commented Jan 27 at 19:31
  • @DMan it's not clear what kind of help you want. If you want us to show you how to use the Parallel.ForEach with async, we simply can't, because it's not possible. If you want us to show you how to adapt your code to use the Parallel.ForEachAsync instead of the Parallel.ForEach, this is something that we can do, but you have to ask for it explicitly. Before asking it, are you sure that the Parallel.ForEachAsync is available for your project? You have to target the .NET 6 or later to use it. What .NET platform and version are you targeting? Commented Jan 27 at 19:38
  • @TheodorZoulias .NET 8.0. There may be multiple issues but if I don't know if there are or what they are, I am obviously unable to ask about those. For example, if using async is not possible, why is Parallel.ForEach<Website>(_websites, async (item) suggested by the documentation and Visual Studio? Likewise, the synchronous code part works in a console app but not in Windows Forms. I have not been able to find out why. Commented Jan 27 at 19:58

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.