PrimuS
PrimuS

Reputation: 2683

Async function with DownloadStringAsync

What I am trying

In my WPF I crawl my internal network and see if an IP/URL can be accessed. So I call 255 IPs with DownloadStringAsync in a loop. Now, whenever I receive a response or a timeout I want to update my progressbar (which has a max of 255). My code seems to work for the first x (I believe something like 10-15) IPs as I see the progressbar moving

The Call-Loop

try
   {
     while (i < 255)
     {
         var client = new WebClient();
         client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(GetInfo);
         client.DownloadStringAsync(new Uri("http://" + myIPNet + "." + i + ":1400/status/topology"));
         i++;
     }
   }
   catch (Exception ex)
   {
       Console.WriteLine(ex.Message);
   }

The GetInfo Function

private void GetInfo(object sender, DownloadStringCompletedEventArgs e)
{
    /* Each call, count up Global Ip Counter and move progressBar */
    countIps++;
    pbSearch.Value = countIps;

    /* Do Stuff with e.Result */
    ...

    /* Check if we have all IPs in net already */
    if (countIps == 255)
    {
        /* Reset progressBar */
        pbSearch.Value = 0;

        /* Enable Button  */
        btnGetAll.IsEnabled = true;
     }
 }

I found this Asynchronous File Download with Progress Bar and I think I understand this answer https://stackoverflow.com/a/9459441/1092632 but this has the progressbar updated for one download in progress, any ideas on how to "convert" this to my case?

Upvotes: 0

Views: 282

Answers (1)

ibebbs
ibebbs

Reputation: 1993

I think the main issue with your code here is that you're expecting the DownloadStringAsync to block until the DownloadStringCompleted event has fired. This does not happen as per the description of the function:

Downloads the resource specified as a Uri. This method does not block the calling thread.

In effect you are rapidly making 255 concurrent web calls and then dropping out the bottom of the loop before they're completed.

As blocking using the Event-based Asynchronous Pattern (EAP) would require significant re-architecture of your code (and significantly increase complexity) I would encourage you to look at using Task-based Asynchronous Pattern instead. Stephen Toub has an excellent guide to converting the WebClient from EAP to TAP patterns here.

Using this you could rewrite you code as follows and should meet significantly more success:

var client = new WebClient();

while (i < 255)
{
    try
    {
        byte[] result = await client.DownloadDataTask(new Uri("http://" + myIPNet + "." + i + ":1400/status/topology"));
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }

    pbSearch.Value = i++;
}

/* Now we have all IPs */
/* Reset progressBar */
pbSearch.Value = 0;

/* Enable Button  */
btnGetAll.IsEnabled = true;

Hope it helps.

Upvotes: 1

Related Questions