Partager via


Gestion de la réentrance dans Async Apps (Visual Basic)

Lorsque vous incluez du code asynchrone dans votre application, vous devez envisager et éventuellement empêcher la réentrance, ce qui fait référence à la réentération d’une opération asynchrone avant sa fin. Si vous n’identifiez pas et ne gérez pas les possibilités de réentrance, cela peut entraîner des résultats inattendus.

Remarque

Pour exécuter l’exemple, vous devez disposer de Visual Studio 2012 ou version ultérieure et du .NET Framework 4.5 ou ultérieur installé sur votre ordinateur.

Remarque

Transport Layer Security (TLS) version 1.2 est désormais la version minimale à utiliser dans le développement de votre application. Si votre application cible une version .NET Framework antérieure à la version 4.7, reportez-vous à l’article suivant pour connaître les meilleures pratiques tls (Transport Layer Security) avec le .NET Framework.

Reconnaissance de la réentrance

Dans l’exemple de cette rubrique, les utilisateurs choisissent un bouton Démarrer pour lancer une application asynchrone qui télécharge une série de sites web et calcule le nombre total d’octets téléchargés. Une version synchrone de l’exemple répond de la même façon, quel que soit le nombre de fois qu’un utilisateur choisit le bouton, car, après la première fois, le thread d’interface utilisateur ignore ces événements jusqu’à ce que l’application se termine en cours d’exécution. Dans une application asynchrone, toutefois, le thread d’interface utilisateur continue de répondre et vous pouvez réentérer l’opération asynchrone avant qu’elle ne soit terminée.

L’exemple suivant montre la sortie attendue si l’utilisateur choisit le bouton Démarrer une seule fois. Une liste des sites web téléchargés apparaît avec la taille, en octets, de chaque site. Le nombre total d’octets apparaît à la fin.

1. msdn.microsoft.com/library/hh191443.aspx                83732
2. msdn.microsoft.com/library/aa578028.aspx               205273
3. msdn.microsoft.com/library/jj155761.aspx                29019
4. msdn.microsoft.com/library/hh290140.aspx               117152
5. msdn.microsoft.com/library/hh524395.aspx                68959
6. msdn.microsoft.com/library/ms404677.aspx               197325
7. msdn.microsoft.com                                            42972
8. msdn.microsoft.com/library/ff730837.aspx               146159

TOTAL bytes returned:  890591

Toutefois, si l’utilisateur choisit le bouton plusieurs fois, le gestionnaire d’événements est appelé à plusieurs reprises et le processus de téléchargement est retranscrit chaque fois. Par conséquent, plusieurs opérations asynchrones s’exécutent en même temps, la sortie entrelace les résultats et le nombre total d’octets est déroutant.

1. msdn.microsoft.com/library/hh191443.aspx                83732
2. msdn.microsoft.com/library/aa578028.aspx               205273
3. msdn.microsoft.com/library/jj155761.aspx                29019
4. msdn.microsoft.com/library/hh290140.aspx               117152
5. msdn.microsoft.com/library/hh524395.aspx                68959
1. msdn.microsoft.com/library/hh191443.aspx                83732
2. msdn.microsoft.com/library/aa578028.aspx               205273
6. msdn.microsoft.com/library/ms404677.aspx               197325
3. msdn.microsoft.com/library/jj155761.aspx                29019
7. msdn.microsoft.com                                            42972
4. msdn.microsoft.com/library/hh290140.aspx               117152
8. msdn.microsoft.com/library/ff730837.aspx               146159

TOTAL bytes returned:  890591

5. msdn.microsoft.com/library/hh524395.aspx                68959
1. msdn.microsoft.com/library/hh191443.aspx                83732
2. msdn.microsoft.com/library/aa578028.aspx               205273
6. msdn.microsoft.com/library/ms404677.aspx               197325
3. msdn.microsoft.com/library/jj155761.aspx                29019
4. msdn.microsoft.com/library/hh290140.aspx               117152
7. msdn.microsoft.com                                            42972
5. msdn.microsoft.com/library/hh524395.aspx                68959
8. msdn.microsoft.com/library/ff730837.aspx               146159

TOTAL bytes returned:  890591

6. msdn.microsoft.com/library/ms404677.aspx               197325
7. msdn.microsoft.com                                            42972
8. msdn.microsoft.com/library/ff730837.aspx               146159

TOTAL bytes returned:  890591

Vous pouvez consulter le code qui produit cette sortie en faisant défiler jusqu’à la fin de cette rubrique. Vous pouvez tester le code en téléchargeant la solution sur votre ordinateur local, puis en exécutant le projet WebsiteDownload ou en utilisant le code à la fin de cette rubrique pour créer votre propre projet Pour plus d’informations et d’instructions, consultez Révision et exécution de l’exemple d’application.

Gestion de la réentrance

Vous pouvez gérer la réentrance de différentes façons, en fonction de ce que vous souhaitez que votre application fasse. Cette rubrique présente les exemples suivants :

Désactiver le bouton Démarrer

Vous pouvez bloquer le bouton Démarrer pendant l’exécution d’une opération en désactivant le bouton en haut du StartButton_Click gestionnaire d’événements. Vous pouvez ensuite réactiver le bouton à partir d’un Finally bloc lorsque l’opération se termine afin que les utilisateurs puissent réexécuter l’application.

Le code suivant montre ces modifications, qui sont marquées avec des astérisques. Vous pouvez ajouter les modifications au code à la fin de cette rubrique, ou télécharger l’application terminée à partir d’exemples asynchrones : réentrance dans les applications de bureau .NET. Le nom du projet est DisableStartButton.

Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)
    ' This line is commented out to make the results clearer in the output.
    'ResultsTextBox.Text = ""

    ' ***Disable the Start button until the downloads are complete.
    StartButton.IsEnabled = False

    Try
        Await AccessTheWebAsync()

    Catch ex As Exception
        ResultsTextBox.Text &= vbCrLf & "Downloads failed."
    ' ***Enable the Start button in case you want to run the program again.
    Finally
        StartButton.IsEnabled = True

    End Try
End Sub

En raison des modifications, le bouton ne répond pas lors AccessTheWebAsync du téléchargement des sites web, de sorte que le processus ne peut pas être recréé.

Annuler et redémarrer l’opération

Au lieu de désactiver le bouton Démarrer , vous pouvez conserver le bouton actif, mais, si l’utilisateur choisit à nouveau ce bouton, annulez l’opération déjà en cours d’exécution et laissez l’opération la plus récente démarrer.

Pour plus d’informations sur l’annulation, consultez Fine-Tuning Votre application asynchrone (Visual Basic).

Pour configurer ce scénario, apportez les modifications suivantes au code de base fourni dans Révision et exécution de l’exemple d’application. Vous pouvez également télécharger l’application terminée à partir d’exemples asynchrones : Réentrancy dans les applications de bureau .NET. Le nom de ce projet est CancelAndRestart.

  1. Déclarez une CancellationTokenSource variable, ctsqui est dans l’étendue de toutes les méthodes.

    Class MainWindow // Or Class MainPage
    
        ' *** Declare a System.Threading.CancellationTokenSource.
        Dim cts As CancellationTokenSource
    
  2. Dans StartButton_Click, déterminez si une opération est déjà en cours. Si la valeur est ctsNothing, aucune opération n’est déjà active. Si la valeur n’est pas Nothing, l’opération en cours d’exécution est annulée.

    ' *** If a download process is already underway, cancel it.
    If cts IsNot Nothing Then
        cts.Cancel()
    End If
    
  3. Définissez cts sur une valeur différente qui représente le processus actuel.

    ' *** Now set cts to cancel the current process if the button is chosen again.
    Dim newCTS As CancellationTokenSource = New CancellationTokenSource()
    cts = newCTS
    
  4. À la fin de StartButton_Click, le processus actuel est terminé, donc définissez la valeur de cts retour sur Nothing.

    ' *** When the process completes, signal that another process can proceed.
    If cts Is newCTS Then
        cts = Nothing
    End If
    

Le code suivant montre toutes les modifications dans StartButton_Click. Les ajouts sont marqués d’astérisques.

Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)

    ' This line is commented out to make the results clearer.
    'ResultsTextBox.Text = ""

    ' *** If a download process is underway, cancel it.
    If cts IsNot Nothing Then
        cts.Cancel()
    End If

    ' *** Now set cts to cancel the current process if the button is chosen again.
    Dim newCTS As CancellationTokenSource = New CancellationTokenSource()
    cts = newCTS

    Try
        ' *** Send a token to carry the message if the operation is canceled.
        Await AccessTheWebAsync(cts.Token)

    Catch ex As OperationCanceledException
        ResultsTextBox.Text &= vbCrLf & "Download canceled." & vbCrLf

    Catch ex As Exception
        ResultsTextBox.Text &= vbCrLf & "Downloads failed."
    End Try

    ' *** When the process is complete, signal that another process can proceed.
    If cts Is newCTS Then
        cts = Nothing
    End If
End Sub

Dans AccessTheWebAsync, apportez les modifications suivantes.

  • Ajoutez un paramètre pour accepter le jeton d’annulation à partir de StartButton_Click.

  • Utilisez la GetAsync méthode pour télécharger les sites web, car GetAsync accepte un CancellationToken argument.

  • Avant d’appeler DisplayResults pour afficher les résultats de chaque site web téléchargé, vérifiez ct que l’opération actuelle n’a pas été annulée.

Le code suivant montre ces modifications, qui sont marquées avec des astérisques.

' *** Provide a parameter for the CancellationToken from StartButton_Click.
Private Async Function AccessTheWebAsync(ct As CancellationToken) As Task

    ' Declare an HttpClient object.
    Dim client = New HttpClient()

    ' Make a list of web addresses.
    Dim urlList As List(Of String) = SetUpURLList()

    Dim total = 0
    Dim position = 0

    For Each url In urlList
        ' *** Use the HttpClient.GetAsync method because it accepts a
        ' cancellation token.
        Dim response As HttpResponseMessage = Await client.GetAsync(url, ct)

        ' *** Retrieve the website contents from the HttpResponseMessage.
        Dim urlContents As Byte() = Await response.Content.ReadAsByteArrayAsync()

        ' *** Check for cancellations before displaying information about the
        ' latest site.
        ct.ThrowIfCancellationRequested()

        position += 1
        DisplayResults(url, urlContents, position)

        ' Update the total.
        total += urlContents.Length
    Next

    ' Display the total count for all of the websites.
    ResultsTextBox.Text &=
        String.Format(vbCrLf & vbCrLf & "TOTAL bytes returned:  " & total & vbCrLf)
End Function

Si vous choisissez le bouton Démarrer plusieurs fois pendant l’exécution de cette application, il doit produire des résultats qui ressemblent à la sortie suivante :

1. msdn.microsoft.com/library/hh191443.aspx                83732
2. msdn.microsoft.com/library/aa578028.aspx               205273
3. msdn.microsoft.com/library/jj155761.aspx                29019
4. msdn.microsoft.com/library/hh290140.aspx               122505
5. msdn.microsoft.com/library/hh524395.aspx                68959
6. msdn.microsoft.com/library/ms404677.aspx               197325
Download canceled.

1. msdn.microsoft.com/library/hh191443.aspx                83732
2. msdn.microsoft.com/library/aa578028.aspx               205273
3. msdn.microsoft.com/library/jj155761.aspx                29019
Download canceled.

1. msdn.microsoft.com/library/hh191443.aspx                83732
2. msdn.microsoft.com/library/aa578028.aspx               205273
3. msdn.microsoft.com/library/jj155761.aspx                29019
4. msdn.microsoft.com/library/hh290140.aspx               117152
5. msdn.microsoft.com/library/hh524395.aspx                68959
6. msdn.microsoft.com/library/ms404677.aspx               197325
7. msdn.microsoft.com                                            42972
8. msdn.microsoft.com/library/ff730837.aspx               146159

TOTAL bytes returned:  890591

Pour éliminer les listes partielles, supprimez les marques de commentaire de la première ligne de code pour StartButton_Click effacer la zone de texte chaque fois que l’utilisateur redémarre l’opération.

Exécuter plusieurs opérations et mettre en file d’attente la sortie

Ce troisième exemple est le plus compliqué dans lequel l’application démarre une autre opération asynchrone chaque fois que l’utilisateur choisit le bouton Démarrer , et toutes les opérations s’exécutent à la fin. Toutes les opérations demandées téléchargent des sites web à partir de la liste de manière asynchrone, mais la sortie des opérations est présentée séquentiellement. Autrement dit, l’activité de téléchargement réelle est entrelacée, comme le montre la sortie de La reconnaissance de la réentrance , mais la liste des résultats pour chaque groupe est présentée séparément.

Les opérations partagent un contrôle global Task, pendingWorkqui sert de gardien de contrôle pour le processus d’affichage.

Vous pouvez exécuter cet exemple en collant les modifications apportées au code de génération de l’application, ou vous pouvez suivre les instructions de téléchargement de l’application pour télécharger l’exemple, puis exécuter le projet QueueResults.

La sortie suivante montre le résultat si l’utilisateur choisit le bouton Démarrer une seule fois. L’étiquette de lettre, A, indique que le résultat provient de la première fois que le bouton Démarrer est choisi. Les nombres indiquent l’ordre des URL dans la liste des cibles de téléchargement.

#Starting group A.
#Task assigned for group A.

A-1. msdn.microsoft.com/library/hh191443.aspx                87389
A-2. msdn.microsoft.com/library/aa578028.aspx               209858
A-3. msdn.microsoft.com/library/jj155761.aspx                30870
A-4. msdn.microsoft.com/library/hh290140.aspx               119027
A-5. msdn.microsoft.com/library/hh524395.aspx                71260
A-6. msdn.microsoft.com/library/ms404677.aspx               199186
A-7. msdn.microsoft.com                                            53266
A-8. msdn.microsoft.com/library/ff730837.aspx               148020

TOTAL bytes returned:  918876

#Group A is complete.

Si l’utilisateur choisit le bouton Démarrer trois fois, l’application produit une sortie semblable aux lignes suivantes. Les lignes d’informations qui commencent par un signe de livre (#) tracent la progression de l’application.

#Starting group A.
#Task assigned for group A.

A-1. msdn.microsoft.com/library/hh191443.aspx                87389
A-2. msdn.microsoft.com/library/aa578028.aspx               207089
A-3. msdn.microsoft.com/library/jj155761.aspx                30870
A-4. msdn.microsoft.com/library/hh290140.aspx               119027
A-5. msdn.microsoft.com/library/hh524395.aspx                71259
A-6. msdn.microsoft.com/library/ms404677.aspx               199185

#Starting group B.
#Task assigned for group B.

A-7. msdn.microsoft.com                                            53266

#Starting group C.
#Task assigned for group C.

A-8. msdn.microsoft.com/library/ff730837.aspx               148010

TOTAL bytes returned:  916095

B-1. msdn.microsoft.com/library/hh191443.aspx                87389
B-2. msdn.microsoft.com/library/aa578028.aspx               207089
B-3. msdn.microsoft.com/library/jj155761.aspx                30870
B-4. msdn.microsoft.com/library/hh290140.aspx               119027
B-5. msdn.microsoft.com/library/hh524395.aspx                71260
B-6. msdn.microsoft.com/library/ms404677.aspx               199186

#Group A is complete.

B-7. msdn.microsoft.com                                            53266
B-8. msdn.microsoft.com/library/ff730837.aspx               148010

TOTAL bytes returned:  916097

C-1. msdn.microsoft.com/library/hh191443.aspx                87389
C-2. msdn.microsoft.com/library/aa578028.aspx               207089

#Group B is complete.

C-3. msdn.microsoft.com/library/jj155761.aspx                30870
C-4. msdn.microsoft.com/library/hh290140.aspx               119027
C-5. msdn.microsoft.com/library/hh524395.aspx                72765
C-6. msdn.microsoft.com/library/ms404677.aspx               199186
C-7. msdn.microsoft.com                                            56190
C-8. msdn.microsoft.com/library/ff730837.aspx               148010

TOTAL bytes returned:  920526

#Group C is complete.

Les groupes B et C commencent avant la fin du groupe A, mais la sortie de chaque groupe apparaît séparément. Toute la sortie du groupe A s’affiche en premier, suivie de toutes les sorties du groupe B, puis de toutes les sorties du groupe C. L’application affiche toujours les groupes dans l’ordre et, pour chaque groupe, affiche toujours les informations sur les sites web individuels dans l’ordre dans lequel les URL apparaissent dans la liste des URL.

Toutefois, vous ne pouvez pas prédire l’ordre dans lequel les téléchargements se produisent réellement. Une fois plusieurs groupes démarrés, les tâches de téléchargement qu’elles génèrent sont toutes actives. Vous ne pouvez pas supposer que A-1 sera téléchargé avant B-1, et vous ne pouvez pas supposer que A-1 sera téléchargé avant A-2.

Définitions globales

L’exemple de code contient les deux déclarations globales suivantes qui sont visibles à partir de toutes les méthodes.

Class MainWindow    ' Class MainPage in Windows Store app.

    ' ***Declare the following variables where all methods can access them.
    Private pendingWork As Task = Nothing
    Private group As Char = ChrW(AscW("A") - 1)

La Task variable, pendingWorksupervise le processus d’affichage et empêche tout groupe d’interrompre l’opération d’affichage d’un autre groupe. Variable de caractère, groupétiquette la sortie de différents groupes pour vérifier que les résultats apparaissent dans l’ordre attendu.

Gestionnaire d’événements Click

Le gestionnaire d’événements, incrémente StartButton_Clickla lettre de groupe chaque fois que l’utilisateur choisit le bouton Démarrer . Ensuite, le gestionnaire appelle AccessTheWebAsync pour exécuter l’opération de téléchargement.

Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)
    ' ***Verify that each group's results are displayed together, and that
    ' the groups display in order, by marking each group with a letter.
    group = ChrW(AscW(group) + 1)
    ResultsTextBox.Text &= String.Format(vbCrLf & vbCrLf & "#Starting group {0}.", group)

    Try
        ' *** Pass the group value to AccessTheWebAsync.
        Dim finishedGroup As Char = Await AccessTheWebAsync(group)

        ' The following line verifies a successful return from the download and
        ' display procedures.
        ResultsTextBox.Text &= String.Format(vbCrLf & vbCrLf & "#Group {0} is complete." & vbCrLf, finishedGroup)

    Catch ex As Exception
        ResultsTextBox.Text &= vbCrLf & "Downloads failed."

    End Try
End Sub

Méthode AccessTheWebAsync

Cet exemple fractionne en AccessTheWebAsync deux méthodes. La première méthode, AccessTheWebAsync, démarre toutes les tâches de téléchargement pour un groupe et configure pendingWork pour contrôler le processus d’affichage. La méthode utilise une requête LINQ (Language Integrated Query) et ToArray démarre toutes les tâches de téléchargement en même temps.

AccessTheWebAsync appelle FinishOneGroupAsync ensuite pour attendre la fin de chaque téléchargement et afficher sa longueur.

FinishOneGroupAsync retourne une tâche affectée dans pendingWorkAccessTheWebAsync. Cette valeur empêche l’interruption d’une autre opération avant la fin de la tâche.

Private Async Function AccessTheWebAsync(grp As Char) As Task(Of Char)

    Dim client = New HttpClient()

    ' Make a list of the web addresses to download.
    Dim urlList As List(Of String) = SetUpURLList()

    ' ***Kick off the downloads. The application of ToArray activates all the download tasks.
    Dim getContentTasks As Task(Of Byte())() =
        urlList.Select(Function(addr) client.GetByteArrayAsync(addr)).ToArray()

    ' ***Call the method that awaits the downloads and displays the results.
    ' Assign the Task that FinishOneGroupAsync returns to the gatekeeper task, pendingWork.
    pendingWork = FinishOneGroupAsync(urlList, getContentTasks, grp)

    ResultsTextBox.Text &=
        String.Format(vbCrLf & "#Task assigned for group {0}. Download tasks are active." & vbCrLf, grp)

    ' ***This task is complete when a group has finished downloading and displaying.
    Await pendingWork

    ' You can do other work here or just return.
    Return grp
End Function

FinishOneGroupAsync, méthode

Cette méthode effectue un cycle dans les tâches de téléchargement d’un groupe, en attendant chacune d’elles, en affichant la longueur du site web téléchargé et en ajoutant la longueur au total.

La première instruction utilisée FinishOneGroupAsyncpendingWork pour s’assurer que l’entrée de la méthode n’interfère pas avec une opération qui se trouve déjà dans le processus d’affichage ou qui est déjà en attente. Si une telle opération est en cours, l’opération d’entrée doit attendre son tour.

Private Async Function FinishOneGroupAsync(urls As List(Of String), contentTasks As Task(Of Byte())(), grp As Char) As Task

    ' Wait for the previous group to finish displaying results.
    If pendingWork IsNot Nothing Then
        Await pendingWork
    End If

    Dim total = 0

    ' contentTasks is the array of Tasks that was created in AccessTheWebAsync.
    For i As Integer = 0 To contentTasks.Length - 1
        ' Await the download of a particular URL, and then display the URL and
        ' its length.
        Dim content As Byte() = Await contentTasks(i)
        DisplayResults(urls(i), content, i, grp)
        total += content.Length
    Next

    ' Display the total count for all of the websites.
    ResultsTextBox.Text &=
        String.Format(vbCrLf & vbCrLf & "TOTAL bytes returned:  " & total & vbCrLf)
End Function

Vous pouvez exécuter cet exemple en collant les modifications apportées au code de génération de l’application, ou vous pouvez suivre les instructions de téléchargement de l’application pour télécharger l’exemple, puis exécuter le projet QueueResults.

Points d’intérêt

Les lignes d’informations qui commencent par un signe de livre (#) dans la sortie précisent le fonctionnement de cet exemple.

La sortie affiche les modèles suivants.

  • Un groupe peut être démarré pendant qu’un groupe précédent affiche sa sortie, mais l’affichage de la sortie du groupe précédent n’est pas interrompu.

    #Starting group A.
    #Task assigned for group A. Download tasks are active.
    
    A-1. msdn.microsoft.com/library/hh191443.aspx                87389
    A-2. msdn.microsoft.com/library/aa578028.aspx               207089
    A-3. msdn.microsoft.com/library/jj155761.aspx                30870
    A-4. msdn.microsoft.com/library/hh290140.aspx               119037
    A-5. msdn.microsoft.com/library/hh524395.aspx                71260
    
    #Starting group B.
    #Task assigned for group B. Download tasks are active.
    
    A-6. msdn.microsoft.com/library/ms404677.aspx               199186
    A-7. msdn.microsoft.com                                            53078
    A-8. msdn.microsoft.com/library/ff730837.aspx               148010
    
    TOTAL bytes returned:  915919
    
    B-1. msdn.microsoft.com/library/hh191443.aspx                87388
    B-2. msdn.microsoft.com/library/aa578028.aspx               207089
    B-3. msdn.microsoft.com/library/jj155761.aspx                30870
    
    #Group A is complete.
    
    B-4. msdn.microsoft.com/library/hh290140.aspx               119027
    B-5. msdn.microsoft.com/library/hh524395.aspx                71260
    B-6. msdn.microsoft.com/library/ms404677.aspx               199186
    B-7. msdn.microsoft.com                                            53078
    B-8. msdn.microsoft.com/library/ff730837.aspx               148010
    
    TOTAL bytes returned:  915908
    
  • La pendingWork tâche est Nothing au début du FinishOneGroupAsync groupe A, qui a démarré en premier. Le groupe A n’a pas encore terminé une expression await lorsqu’elle atteint FinishOneGroupAsync. Par conséquent, le contrôle n’a pas retourné à AccessTheWebAsync, et la première affectation à pendingWork n’a pas eu lieu.

  • Les deux lignes suivantes apparaissent toujours ensemble dans la sortie. Le code n’est jamais interrompu entre le démarrage de l’opération d’un groupe et StartButton_Click l’affectation d’une tâche pour le groupe à pendingWork.

    #Starting group B.
    #Task assigned for group B. Download tasks are active.
    

    Une fois qu’un groupe entre StartButton_Click, l’opération ne termine pas une expression await tant que l’opération n’entre pas FinishOneGroupAsync. Par conséquent, aucune autre opération ne peut prendre le contrôle pendant ce segment de code.

Examen et exécution de l’exemple d’application

Pour mieux comprendre l’exemple d’application, vous pouvez le télécharger, le générer vous-même ou passer en revue le code à la fin de cette rubrique sans implémenter l’application.

Remarque

Pour exécuter l’exemple en tant qu’application de bureau Windows Presentation Foundation (WPF), vous devez disposer de Visual Studio 2012 ou version ultérieure et du .NET Framework 4.5 ou ultérieur installé sur votre ordinateur.

Téléchargement de l’application

  1. Téléchargez le fichier compressé à partir d’exemples Async : réentrance dans les applications de bureau .NET.

  2. Décompressez le fichier que vous avez téléchargé, puis démarrez Visual Studio.

  3. Dans la barre de menus, choisissez Fichier, Ouvrir, Projet/Solution.

  4. Accédez au dossier qui contient l’exemple de code compressé, puis ouvrez le fichier de solution (.sln).

  5. Dans l’Explorateur de solutions, ouvrez le menu contextuel du projet que vous souhaitez exécuter, puis choisissez Définir comme StartUpProject.

  6. Choisissez les touches Ctrl+F5 à générer et exécuter le projet.

Génération de l’application

La section suivante fournit le code permettant de générer l’exemple en tant qu’application WPF.

Pour créer une application WPF
  1. Démarrez Visual Studio.

  2. Dans le menu principal, sélectionnez Fichier, Nouveau, Projet.

    La boîte de dialogue Nouveau projet s’ouvre.

  3. Dans le volet Modèles installés , développez Visual Basic, puis Développez Windows.

  4. Dans la liste des types de projets, choisissez Application WPF.

  5. Nommez le projet WebsiteDownloadWPF, choisissez .NET Framework version 4.6 ou ultérieure, puis cliquez sur le bouton OK .

    Le nouveau projet s’affiche dans l’Explorateur de solutions.

  6. Dans l'éditeur de code Visual Studio, choisissez l'onglet MainWindow.xaml .

    Si l’onglet n’est pas visible, ouvrez le menu contextuel de MainWindow.xaml dans l’Explorateur de solutions, puis choisissez Afficher le code.

  7. Dans la vue XAML de MainWindow.xaml, remplacez le code par le code suivant.

    <Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:WebsiteDownloadWPF"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid Width="517" Height="360">
            <Button x:Name="StartButton" Content="Start" HorizontalAlignment="Left" Margin="-1,0,0,0" VerticalAlignment="Top" Click="StartButton_Click" Height="53" Background="#FFA89B9B" FontSize="36" Width="518"  />
            <TextBox x:Name="ResultsTextBox" HorizontalAlignment="Left" Margin="-1,53,0,-36" TextWrapping="Wrap" VerticalAlignment="Top" Height="343" FontSize="10" ScrollViewer.VerticalScrollBarVisibility="Visible" Width="518" FontFamily="Lucida Console" />
        </Grid>
    </Window>
    

    Une fenêtre simple qui contient une zone de texte et un bouton s’affiche dans la vue Création de MainWindow.xaml.

  8. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur Références , puis sélectionnez Ajouter une référence.

    Ajoutez une référence pour System.Net.Http, si elle n’est pas déjà sélectionnée.

  9. Dans l’Explorateur de solutions, ouvrez le menu contextuel pour MainWindow.xaml.vb, puis choisissez Afficher le code.

  10. Dans MainWindow.xaml.vb, remplacez le code par le code suivant.

    ' Add the following Imports statements, and add a reference for System.Net.Http.
    Imports System.Net.Http
    Imports System.Threading
    
    Class MainWindow
    
        Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)
            System.Net.ServicePointManager.SecurityProtocol = System.Net.ServicePointManager.SecurityProtocol Or System.Net.SecurityProtocolType.Tls12
    
            ' This line is commented out to make the results clearer in the output.
            'ResultsTextBox.Text = ""
    
            Try
                Await AccessTheWebAsync()
    
            Catch ex As Exception
                ResultsTextBox.Text &= vbCrLf & "Downloads failed."
    
            End Try
        End Sub
    
        Private Async Function AccessTheWebAsync() As Task
    
            ' Declare an HttpClient object.
            Dim client = New HttpClient()
    
            ' Make a list of web addresses.
            Dim urlList As List(Of String) = SetUpURLList()
    
            Dim total = 0
            Dim position = 0
    
            For Each url In urlList
                ' GetByteArrayAsync returns a task. At completion, the task
                ' produces a byte array.
                Dim urlContents As Byte() = Await client.GetByteArrayAsync(url)
    
                position += 1
                DisplayResults(url, urlContents, position)
    
                ' Update the total.
                total += urlContents.Length
            Next
    
            ' Display the total count for all of the websites.
            ResultsTextBox.Text &=
                String.Format(vbCrLf & vbCrLf & "TOTAL bytes returned:  " & total & vbCrLf)
        End Function
    
        Private Function SetUpURLList() As List(Of String)
            Dim urls = New List(Of String) From
            {
                "https://msdn.microsoft.com/library/hh191443.aspx",
                "https://msdn.microsoft.com/library/aa578028.aspx",
                "https://msdn.microsoft.com/library/jj155761.aspx",
                "https://msdn.microsoft.com/library/hh290140.aspx",
                "https://msdn.microsoft.com/library/hh524395.aspx",
                "https://msdn.microsoft.com/library/ms404677.aspx",
                "https://msdn.microsoft.com",
                "https://msdn.microsoft.com/library/ff730837.aspx"
            }
            Return urls
        End Function
    
        Private Sub DisplayResults(url As String, content As Byte(), pos As Integer)
            ' Display the length of each website. The string format is designed
            ' to be used with a monospaced font, such as Lucida Console or
            ' Global Monospace.
    
            ' Strip off the "http:'".
            Dim displayURL = url.Replace("https://", "")
            ' Display position in the URL list, the URL, and the number of bytes.
            ResultsTextBox.Text &= String.Format(vbCrLf & "{0}. {1,-58} {2,8}", pos, displayURL, content.Length)
        End Sub
    End Class
    
  11. Choisissez les touches Ctrl+F5 pour exécuter le programme, puis choisissez le bouton Démarrer plusieurs fois.

  12. Apportez les modifications du bouton Démarrer, Annuler et Redémarrer l’opération, ou exécutez plusieurs opérations et mettent en file d’attente la sortie pour gérer la réentrance.

Voir aussi