C#C
C#2y ago
stigzler

✅ Using IProgress with await Task.WhenAll(tasks);

I am trying to introduce a IProgress object into the code below. Can't for the life of me figure how to do it. I need the code this way (rather than via a foreach loop) because I am querying an API which limits the number of concurrent threads.
The IProgress objects main ProgressEventArgs will be how many items have been processed and also the url used in each task instance. Thus I need some way to keep track of how many taks have been completed. Any steers? The code:

    
public class Scraper
{
    
    private SemaphoreSlim semaphoreSlim = 7;
    public void Scraper(int concurrentThreads)
    {
        semaphoreSlim = new SemaphoreSlim(concurrentThreads);
        ServicePointManager.FindServicePoint(new Uri(baseUrl)).ConnectionLimit = concurrentThreads;
    }

    public async Task<List<ApiGetStringOutcome>> GetStringsFromUrlList(List<string> apiUrls)
    {
        List<Task<ApiGetStringOutcome>> tasks = new List<Task<ApiGetStringOutcome>>();

        foreach (string apiUrl in apiUrls)
        {
            tasks.Add(GetStringDataAsync(apiUrl));
        }

        await Task.WhenAll(tasks);

        return new List<ApiGetStringOutcome>(tasks.Select(t => t.Result));
    }

    private async Task<ApiGetStringOutcome> GetStringDataAsync(string apiUrl, ApiGameSearchParameters gameSearchParameters = null)
    {
        await semaphoreSlim.WaitAsync(); // Wait until semaphore is available

        try
        {
            HttpResponseMessage response = await httpClient.GetAsync(apiUrl);
        }
        catch (Exception ex)
        {
            // Stuff here
        }
        finally
        {
            semaphoreSlim.Release();
        }
    }
}

public class MainApp
{
    public void Start()
    {        
        // blah...
        getStringOutcomes = await Task.Run(() => apiDataService.GetStringsFromUrlList(urlList));
    }
    
}
Was this page helpful?