Obtenir des mises à jour de progression à l'aide de HttpWebRequest et de TPL (tâches)

Je voudrais suivre la progression d'un téléchargement se déroulant sur un fil séparé. Je sais que System.Net.WebClient a une méthode DownloadStringAsync, mais elle ne fonctionne pas directement avec les nouveaux types de TPL (TaskFactory, Task, etc.).

  • La progression peut-elle être suivie en utilisant les classes HttpRequest et HttpResponse?
  • Quelle est la meilleure classe pour suivre les progrès? Moins il y a de frais généraux, mieux c'est.
  • Y a-t-il des moments où la taille de la réponse est inconnue, alias, la progression ne peut pas être suivie?
  • Quelle est la meilleure façon de se synchroniser avec le thread de l'interface utilisateur à chaque fois que des progrès sont réalisés?

La plupart des exemples montrent que les tâches ne mettent à jour l'interface utilisateur qu'une fois la tâche complète terminée. Ces exemples utilisent des suites prenant un contexte de synchronisation d'interface utilisateur qui évite de devoir travailler directement avec un Dispatcher.

L'idée est de montrer une vue en grille (en WPF) avec tous les téléchargements avec des barres de progression. Je vais ajouter de nouvelles lignes et mettre à jour les barres de progression tout le temps. J'essaie d'éviter de transformer ce code en bazar.

0

1 Réponses

DownloadStringAsync et les autres méthodes d'événement fonctionnent très bien avec TPL dans .NET 4.0 (vérifiez EAP et TPL). En général, TPL prend en charge la programmation asynchrone des événements via TaskCompletionSource. Le modèle Begin/EndXXX (APM) est pris en charge via la méthode Task.FromAsync. Vous pouvez trouver une description détaillée Programmation asynchrone TPL et traditionnelle .NET .

La bibliothèque ParallelExtensionExtras comporte un ensemble d'extensions WebClient des méthodes telles que DownloadStringTask qui renvoient une tâche qui se termine lorsque l'événement approprié est déclenché.

Le code suivant créera une tâche qui se terminera lorsque le téléchargement sera terminé:

    public Task DownloadStringTask(WebClient client,Uri uri)
    {
        var tcs = new TaskCompletionSource();
        client.DownloadStringCompleted += (o, a) => tcs.SetResult(a.Result);
        client.DownloadStringAsync(uri);
        return tcs.Task;
    }

En ce qui concerne la mise à jour de l'interface utilisateur, vous pouvez facilement utiliser l'événement DownloadProgressChanged pour fournir des commentaires, par exemple:

using (var client = new WebClient())
{
    client.DownloadProgressChanged += (o, a) => Console.WriteLine("{0}",a.ProgressPercentage);

    var task = DownloadStringTask(client,new Uri("http://www.stackoverflow.com"));
    var write=task.ContinueWith(t => Console.WriteLine("Got {0} chars", t.Result.Length));
    write.Wait();
    Console.ReadKey();
}

Si vous utilisez la liaison de données pour fournir les valeurs de progression à vos barres de progression, vous pouvez simplement mettre à jour les propriétés de la valeur de progression. Si vous mettez à jour les barres de progression directement (ce qui n'est pas une bonne idée), vous devrez rassembler l'appel sur le thread d'interface utilisateur en utilisant le répartiteur de la barre de progression, par exemple. comme ça

    void UpdateProgress(int percent)
    {
        if (progressBar1.CheckAccess())
            progressBar1.Value = percent;
        else
        {                
            progressBar1.Dispatcher.Invoke(new Action(()=>UpdateProgress(percent)));
        }
    }
    ....
    client.DownloadProgressChanged += (o, a) => UpdateProgress(a.ProgressPercentage);
0
ajouté