Montrant les progrès réalisés en pourcentage alors que le téléchargement et le téléchargement à l'aide de classe HttpWebRequest
Je suis en train de télécharger (dans la même demande à un serveur à l'aide de HttpWebRequest
dans C#
et puisque la taille des données est considérable (en tenant compte de la vitesse du réseau) je voudrais montrer à l'utilisateur comment loin de que le travail est fait et combien il en reste (pas en secondes mais en pourcentage).
J'ai lu quelques exemples d'essayer de mettre en œuvre cette mais aucun d'entre eux montrent tout de la barre de progression. Ils ont tous simplement utiliser async
de ne pas bloquer l'INTERFACE utilisateur alors que c'est un téléchargement. Et ils sont principalement axés sur télécharger /télécharger et aucun d'essayer, y compris dans la même demande.
Depuis que je suis en utilisant .Net 4 comme mon framework cible, je ne peux pas mettre en oeuvre une async
méthode moi-même. Si vous êtes à proposer quoi que ce soit asynchrone, s'il vous plaît utiliser Begin...
méthodes et de ne pas await
mot-clé! Merci.
OriginalL'auteur Mehran | 2013-12-22
Vous devez vous connecter pour publier un commentaire.
Vous allez avoir besoin de savoir quelques petites choses pour être un succès.
Étape 0: conserver la documentation .NET 4.0 pratique:
Si vous regardez la
HttpWebRequest
de la documentation, vous verrez queGetResponse()
a deux même nom de méthodes:BeginGetResponse()
etEndGetResponse()
. Ces méthodes utilisent la plus ancienne .NET un système modèle, connu comme "le modèle IAsyncResult". Il y a des milliers de pages de texte sur ce modèle, et vous pouvez lire des tutoriels si vous souhaitez obtenir des informations détaillées. Voici le crash course:Foo()
, il y a unBeginFoo()
qui peuvent prendre des paramètres et doit retourner un IAsyncResult mise en œuvre. Cette méthode effectue la tâcheFoo()
effectue, mais fait le travail sans bloquer le thread courant.BeginFoo()
prend un AsyncCallback paramètre, il attend de vous fournir un délégué elle appellera quand il est terminé. (C'est l'un de plusieurs façons, à savoir que c'est fini, mais se trouve être la techniqueHttpWebRequest
utilise.)EndFoo()
prend laIAsyncResult
retourné parBeginFoo()
en tant que paramètre et retourne la même choseFoo()
retourne.Ensuite, il y a un piège dont vous devriez être au courant. Les contrôles ont une propriété appelée "fil d'affinité", et cela signifie qu'il n'est valable que pour interagir avec un contrôle si vous travaillez sur le thread qui a créé le contrôle. Ceci est important, parce que la méthode de rappel que vous donnez à
BeginFoo()
n'est pas garanti d'être appelé à partir de ce thread. C'est en fait très facile à gérer:InvokeRequired
de la propriété qui est la seule propriété de l'appeler à partir du fil conducteur de mal. Si elle renvoietrue
, vous savez que vous êtes sur un dangereux fil.Invoke()
méthode qui accepte un délégué paramètre et appellent le délégué sur le thread qui a créé le contrôle.Avec tout ce qui est hors de la voie, nous allons commencer à chercher un peu de code que j'ai écrit dans une simple application WinForms rapport à la progression du téléchargement de la page d'accueil Google. Cela devrait être similaire à un code qui permettra de résoudre votre problème. Ce n'est pas la meilleur code, mais il illustre les concepts. La forme d'une barre de progression nommé
progressBar1
, et j'ai appeléGetWebContent()
à partir d'un clic sur un bouton.Ce code commence la version asynchrone de
GetResponse()
. Nous avons besoin de stocker de la demande et de laIAsyncResult
dans les champs carResponseCallback()
besoins à l'appel deEndGetResponse()
. Tout enGetWebContent()
est sur le thread de l'INTERFACE utilisateur, donc si vous voulez mettre à jour des contrôles qu'il est sécuritaire de le faire ici. Ensuite,ResponseCallback()
:Il est forcé de prendre une
object
paramètre par l'AsyncCallback délégué de la signature, mais je ne suis pas à l'utiliser. Il appelleEndGetResponse()
avec leIAsyncResult
nous avons eu plus tôt, et maintenant nous pouvons procéder comme si nous n'avons pas utilisé un système d'appels. Mais puisque c'est un rappel asynchrone, il pourrait être en cours d'exécution sur un thread de travail, afin de ne pas mettre à jour les contrôles directement ici.De toute façon, il obtient le contenu de la longueur de la réponse, qui est nécessaire si vous souhaitez calculer vos téléchargements en cours. Parfois, l'en-tête qui contient cette information n'est pas présente, et vous obtenez -1. Cela signifie que vous êtes sur votre propre pour les progrès de calcul et vous devrez trouver un autre moyen de connaître la taille totale du fichier que vous avez téléchargé. Dans mon cas, c'était suffisant pour définir la variable à une valeur puisque je n'ai pas de soins sur les données lui-même.
Après, il obtient le flux qui représente la réponse et le passe le long d'une méthode d'assistance que le téléchargement et la production de rapports d'avancement:
Cette méthode pourrait quand même être sur un thread de travail (puisqu'il est appelé par la fonction de rappel) donc c'est pas encore sûr à mettre à jour les contrôles à partir d'ici.
Le code est commun pour des exemples de téléchargement d'un fichier. Il alloue de la mémoire pour stocker le fichier. Il alloue un tampon pour obtenir le fichier de morceaux à partir du flux. Dans une boucle, il saisit un morceau, met le morceau dans l'ensemble, et calcule le pourcentage de progression. Quand il est téléchargé comme autant d'octets qu'il s'attend à obtenir, il se ferme. C'est un peu de difficulté, mais si vous utilisez les astuces qui vous permettent de télécharger un fichier d'un seul coup, vous ne seriez pas en mesure de rapport de progression du téléchargement dans le milieu.
(Une chose, je me sens obligé de souligner: si vos morceaux sont trop petits, vous serez la mise à jour de la barre de progression très rapidement et cela peut encore causer de la forme pour le verrouiller en place. J'ai l'habitude de garder un
Stopwatch
de course et essayer de ne pas mettre à jour les barres de progression de plus de deux fois par seconde, mais il y a d'autres façons de limiter les mises à jour.)De toute façon, la seule chose qui reste est le code qui fait les mises à jour de la barre de progression, et il y a une raison, c'est dans sa propre méthode:
Si
InvokeRequired
retourne vrai, il s'appelle viaInvoke()
. Si elle arrive à être sur le bon thread, il met à jour la barre de progression. Si vous arrive d'être en utilisant WPF, il existe des moyens de maréchal des appels, mais je crois qu'ils arrivent via leDispatcher
objet.Je sais que c'est beaucoup. C'est en partie pourquoi la nouvelle
async
truc est si grande. LeIAsyncResult
modèle est puissant mais n'est pas abstraite de nombreux détails loin de vous. Mais même dans les nouveaux modèles, vous devez garder une trace de quand il est sûr de mettre à jour une barre de progression.Choses à considérer:
GetResponse()
, il sera jeté au lieu de cela lorsque vous appelezEndGetResponse()
.Stream
par la vérification de laLength
bien, mais j'ai trouvé que cela soit fiable. UnStream
est libre de lancerNotSupportedException
ou de retourner une valeur comme la valeur -1 si il n'est pas sûr, et généralement avec des flux de réseau si vous n'êtes pas informés à l'avance de la quantité de données à attendre alors vous ne pouvez continuez à demander, "Est-il plus?"HttpWebRequest.BeginGetRequestStream()
de sorte que vous pouvez de manière asynchrone écrire le fichier que vous avez télécharger. Toutes les mises en garde à propos de la mise à jour des contrôles s'appliquent.async
mécanisme. Pourtant, j'ai appris une chose ou deux à qui je suis reconnaissant. J'ai déjà trouvé un moyen de mesurer les progrès pour télécharger moi, mais je vais attendre que quelqu'un d'autre pour réclamer la prime, par qui je veux dire que la générosité est toujours disponible pour quelqu'un qui mesure le progrès pour charger et télécharger des deux à la fois. Merci pour le post.OriginalL'auteur OwenP
Aussi longtemps que vous définissez HttpWebRequest.ContentLength ou HttpWebRequest.SendChunked avant d'appeler GetRequestStream, les données que vous envoyez sera envoyé au serveur à chaque appel à Flot.[Begin]Écrire. Si vous écrivez le fichier en petits morceaux que l'on suggère, vous pouvez obtenir une idée de combien de temps vous.
C'est une solution pour le téléchargement.
OriginalL'auteur norekhov
La octetsreçus variable qui obtient la valeur de responseStream.Read(buffer, 0, 256); retourne la taille de chaque unique de paquets reçus, et non pas le total ainsi l' (do...while) sera presque toujours retourner vrai résultant dans une boucle infinie, à moins que le contenu téléchargé est si petit que le paquet combiné avec TCP rembourrage finit par être plus grande ou égale à la contentLength.
La seule solution requis est d'avoir une autre variable locale à agir comme un accumulateur de suivre l'avancement total par exemple totalBytesReceived += octetsreçus; et l'utilisation while(totalBytesReceived < contentLength) à la place. J'ai essayé d'utiliser currentIndex à cette fin, cependant, il a été à l'origine de problèmes (télécharger stands), donc une nouvelle variable indépendante a été utilisé.
C'est ce que j'ai fini par utiliser:
}
Autres que le code a vraiment bien travaillé!
OriginalL'auteur Achim