2015-08-13 1 views
2

J'essaie d'obtenir la vitesse de téléchargement réseau de l'utilisateur actuel. Après avoir atteint une impasse avec NetworkInterfaces et tout ce que j'ai essayé, j'ai trouvé une solution en ligne. Je l'ai édité un peu et ça marche très bien mais ce n'est pas asynchrone.C# Vitesse de téléchargement asynchrone

public static void GetDownloadSpeed(this Label lbl) 
{ 
    double[] speeds = new double[5]; 
    for (int i = 0; i < 5; i++) 
    { 
     int fileSize = 407; //Size of File in KB. 
     WebClient client = new WebClient(); 
     DateTime startTime = DateTime.Now; 
     if (!Directory.Exists($"{CurrentDir}/tmp/speedtest")) 
      Directory.CreateDirectory($"{CurrentDir}/tmp/speedtest"); 

     client.DownloadFile(new Uri("https://ajax.googleapis.com/ajax/libs/threejs/r69/three.min.js"), "/tmp/speedtest/three.min.js"); 
     DateTime endTime = DateTime.Now; 
     speeds[i] = Math.Round((fileSize/(endTime - startTime).TotalSeconds)); 
    } 

    lbl.Text = string.Format("{0}KB/s", speeds.Average()); 
} 

Cette fonction est appelée dans un temporisateur à un intervalle de 2 minutes.

MyLbl.GetDownloadSpeed() 

J'ai essayé d'utiliser WebClient.DownloadFileAsync mais qui montre juste le symbol.My illimité prochain essai serait d'utiliser HttpClient mais avant d'aller sur ce que quelqu'un a une méthode recommandée pour obtenir les utilisateurs actuels télécharger la vitesse de manière asynchrone (sans retarder le fil principal de l'interface graphique)?

+0

Vous devez inclure le code que vous avez essayé avec 'DownloadFileAsync'. Je suppose que vous avez provoqué un blocage en appelant 'Result' ou' Wait' quelque part sur la tâche résultante. –

+1

Essayez 'await Task.Run (() => {// votre code}); –

+0

Merci @ PhilippeParé Ça a marché! –

Répondre

3

Comme il a été suggéré que vous pourriez faire une version async de GetDownloadSpeed():

async void GetDownloadSpeedAsync(this Label lbl, Uri address, int numberOfTests) 
    { 
     string directoryName = @"C:\Work\Test\speedTest"; 
     string fileName = "tmp.dat"; 

     if (!Directory.Exists(directoryName)) 
      Directory.CreateDirectory(directoryName); 

     Stopwatch timer = new Stopwatch(); 

     timer.Start(); 

     for (int i = 0; i < numberOfTests; ++i) 
     { 
      using (WebClient client = new WebClient()) 
      { 
       await client.DownloadFileTaskAsync(address, Path.Combine(directoryName, fileName), CancellationToken.None); 
      } 
     } 

     lbl.Text == Convert.ToString(timer.Elapsed.TotalSeconds/numberOfTests); 
    } 

classe WebClient étant relativement ancienne n'a pas awaitableDownloadFileAsync().

ÉDITÉ Comme il a été souligné à juste titre WebClient en fait a une méthode async basée sur les tâches DownloadFileTaskAsync(), que je vous conseille d'utiliser. Le code ci-dessous peut toujours aider à traiter le cas lorsque la méthode async renvoyant Task n'est pas fournie.

Nous pouvons le fixer à l'aide de TaskCompletionSource<T>:

public static class WebClientExtensions 
    { 

     public static Task DownloadFileAwaitableAsync(this WebClient instance, Uri address, 
      string fileName, CancellationToken cancellationToken) 
     { 
      TaskCompletionSource<object> tcs = new TaskCompletionSource<object>(); 

      // Subscribe for completion event 
      instance.DownloadFileCompleted += instance_DownloadFileCompleted; 

      // Setup cancellation 
      var cancellationRegistration = cancellationToken.CanBeCanceled ? (IDisposable)cancellationToken.Register(() => { instance.CancelAsync(); }) : null; 

      // Initiate asyncronous download 
      instance.DownloadFileAsync(address, fileName, Tuple.Create(tcs, cancellationRegistration)); 

      return tcs.Task; 
     } 

     static void instance_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) 
     { 
      ((WebClient)sender).DownloadDataCompleted -= instance_DownloadFileCompleted; 
      var data = (Tuple<TaskCompletionSource<object>, IDisposable>)e.UserState; 
      if (data.Item2 != null) data.Item2.Dispose(); 
      var tcs = data.Item1; 

      if (e.Cancelled) 
      { 
       tcs.TrySetCanceled(); 
      } 
      else if (e.Error != null) 
      { 
       tcs.TrySetException(e.Error); 
      } 
      else 
      { 
       tcs.TrySetResult(null); 
      } 
     } 
    } 
+0

@PeterDuniho: merci pour la correction, la réponse est éditée pour incorporer vos commentaires. – alexm

-1

Essayez `await Task.Run (() => {// votre code});

Modifier: @JustDevInc Je pense toujours que vous devriez utiliser DownloadAsync. Task.Run (délégué) crée un nouveau thread et vous pourriez vouloir éviter cela. Si vous le souhaitez, publiez un peu de votre ancien code afin que nous puissions essayer de le réparer.

Éditer: La première solution s'est avérée être la seule des deux fonctionnant. DownloadFileAsync ne renvoie pas la tâche, donc ne peut pas l'attendre.

+0

J'ai modifié le post original avec mon ancien code –

+0

Essayez de faire 'GetDownloadSpeed'' async', faites-le retourner 'Task' et ensuite' await' sur 'DownloadFileAsync' –

+0

Mais il n'y a rien à attendre? downloadFileAsync renvoie un void –