Procédure pas à pas : accès au Web avec Async et Await (C# et Visual Basic)

Vous pouvez écrire des programmes asynchrones plus facilement et intuitivement à l'aide des fonctionnalités qui sont présentées dans Visual Studio 2012. Vous pouvez écrire le code asynchrone qui ressemble au code synchrone et permet au compilateur degérer les fonctions de rappel difficiles et les suites que le code asynchrone implique généralement.

Consultez Programmation asynchrone avec Async et Await (C# et Visual Basic) pour plus d'informations sur cette fonctionnalité.

Cette procédure pas - à - pas commence par une application synchrone Windows Presentation Foundation (WPF) qui ajoute le nombre d'octets dans une liste de sites Web. La procédure pas à pas convertit ensuite l'application vers une solution asynchrone en utilisant les nouvelles fonctionnalités.

Si vous ne souhaitez pas générer des applications vous-même, vous pouvez télécharger le terme « sample Async : Accès à la procédure de site Web (c et Visual Basic) » de Exemples de code de développement.

Dans cette procédure pas à pas, vous effectuerez les tâches suivantes :

  • Create a WPF application.

  • Design a simple WPF MainWindow window.

  • Add a reference.

  • Add Imports statements or using directives.

  • Create a synchronous solution.

  • Test the synchronous solution.

  • Convert GetURLContents to an asynchronous method.

  • Convert SumPageSizes to an asynchronous method.

  • Convert startButton_Click to an asynchronous method.

  • Test the asynchronous solution.

  • Replace GetURLContentsAsync with a .NET Framework method.

  • Complete Code Examples from the Walkthrough

Composants requis

Visual Studio 2012 doit être installé sur votre ordinateur. Pour plus d'informations, consultez le site Web Microsoft.

Pour créer une application WPF

  1. Démarrez Visual Studio.

  2. Dans la barre de menus, sélectionnez Fichier, Nouveau, Project.

    La boîte de dialogue Nouveau projet s'affiche.

  3. Dans le volet Modèles installés , choisissez Visual Basic ou Visual C#, puis choisissez Application WPF dans la liste des types de projets.

  4. Dans la zone de texte Nom , spécifiez AsyncExampleWPF, puis choisissez le bouton OK .

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

Pour concevoir une MainWindow WPF simple

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

  2. Si la fenêtre Boîte à outils n'est pas visible, ouvrez le menu Affichage , puis choisissez Boîte à outils.

  3. Ajoutez un contrôle Bouton et un contrôle TextBox à la fenêtre MainWindow .

  4. Mettez en surbrillance le contrôle TextBox et, dans la fenêtre Propriétés , définissez les valeurs suivantes :

    • Affectez à la propriété Nom la valeur resultsTextBox.

    • Affectez à la propriété Height la valeur 250.

    • Affectez à la propriété Width la valeur 500.

    • Sous l'onglet Texte , spécifiez une police monospaced, telle que Lucida Console ou Global Monospace.

  5. Mettez en surbrillance le contrôle Button et, dans la fenêtre Propriétés , définissez les valeurs suivantes :

    • Affectez à la propriété Namela valeur startButton.

    • Remplacez la valeur de la propriété Content de Bouton àDémarrer.

  6. Positionnez la zone de texte et le bouton afin qu'ils apparaissent dans la fenêtre MainWindow .

    Pour plus d'informations sur le concepteur WPF XAML, consultez Création d'une interface utilisateur à l'aide du concepteur XAML.

Pour ajouter une référence

  1. Dans Explorateur de solutions, sélectionnez le nom de votre projet.

  2. Dans la barre de menus, cliquez sur Projet, Ajouter une référence.

    La boîte de dialogue Gestionnaire de Références s'affiche.

  3. En haut de la boîte de dialogue, vérifiez que votre projet cible le.NET Framework 4.5.

  4. Dans la zone Assemblies , choisissez framework s'il n'est pas déjà sélectionnez.

  5. Dans la liste des noms, activez la case à cocher System.Net.Http .

  6. Sélectionnez le bouton OK pour fermer la boîte de dialogue.

Pour ajouter les instructions Imports ou les directives using requises

  1. Dans L'Explorateur de solutions, ouvrez le menu contextuel pour MainWindow.xaml.vb ou MainWindow.xaml.cs puis choisissez Afficher le Code.

  2. Ajoutez les instructions Imports (Visual Basic) ou les directives using (C#) suivantes en haut du fichier de code, s´ils ne sont pas déjà présents.

    Imports System.Net.Http
    Imports System.Net
    Imports System.IO
    
    using System.Net.Http;
    using System.Net;
    using System.IO;
    

Pour créer une application synchrone

  1. Dans la fenêtre de conception, MainWindow.xaml, double-cliquez sur le bouton Start pour créer le gestionnaire d'évènement startButton_Click dans MainWindow.xaml.vb ou MainWindow.xaml.cs. Comme alternative, mettez en surbrillance le bouton Start, choisissez l'icône Gestionnaires d'événements pour les éléments sélectionnés dans la fenêtre Propriétés , puis entrez startButton_Click dans la zone de texte Cliquer .

  2. Dans MainWindow.xaml.vb ou MainWindow.xaml.cs, copiez le code suivant dans le corps de startButton_Click.

    resultsTextBox.Clear()
    SumPageSizes()
    resultsTextBox.Text &= vbCrLf & "Control returned to startButton_Click."
    
    resultsTextBox.Clear();
    SumPageSizes();
    resultsTextBox.Text += "\r\nControl returned to startButton_Click.";
    

    Le code appelle la méthode qui gère l'application, SumPageSizes et affiche un message lorsque le contrôle revient à startButton_Click .

  3. Le code pour la solution synchrone contient les quatre méthodes suivantes :

    • SumPageSizes, qui obtient une liste des URLs des pages Web depuis SetUpURLList puis appelle GetURLContents et DisplayResults pour traiter chaque URL.

    • SetUpURLList, qui crée et retourne une liste d'adresses Web.

    • GetURLContents, qui télécharge le contenu de chaque site Web et retourne le contenu sous la forme d'un tableau d'octets.

    • DisplayResults qui affiche le nombre d'octets dans le tableau d'octets pour chaque URL.

    Copiez les quatre méthodes suivantes et collez-les dans le gestionnaire d'événements startButton_Click dans MainWindow.xaml.vb ou MainWindow.xaml.cs.

    Private Sub SumPageSizes()
    
        ' Make a list of web addresses. 
        Dim urlList As List(Of String) = SetUpURLList()
    
        Dim total = 0
        For Each url In urlList
            ' GetURLContents returns the contents of url as a byte array. 
            Dim urlContents As Byte() = GetURLContents(url)
    
            DisplayResults(url, urlContents)
    
            ' Update the total.
            total += urlContents.Length
        Next 
    
        ' Display the total count for all of the web addresses.
        resultsTextBox.Text &= String.Format(vbCrLf & vbCrLf & "Total bytes returned:  {0}" & vbCrLf, total)
    End Sub 
    
    
    Private Function SetUpURLList() As List(Of String)
    
        Dim urls = New List(Of String) From
            {
                "https://msdn.microsoft.com/library/windows/apps/br211380.aspx",
                "https://msdn.microsoft.com",
                "https://msdn.microsoft.com/en-us/library/hh290136.aspx",
                "https://msdn.microsoft.com/en-us/library/ee256749.aspx",
                "https://msdn.microsoft.com/en-us/library/hh290138.aspx",
                "https://msdn.microsoft.com/en-us/library/hh290140.aspx",
                "https://msdn.microsoft.com/en-us/library/dd470362.aspx",
                "https://msdn.microsoft.com/en-us/library/aa578028.aspx",
                "https://msdn.microsoft.com/en-us/library/ms404677.aspx",
                "https://msdn.microsoft.com/en-us/library/ff730837.aspx"
            }
        Return urls
    End Function 
    
    
    Private Function GetURLContents(url As String) As Byte()
    
        ' The downloaded resource ends up in the variable named content. 
        Dim content = New MemoryStream()
    
        ' Initialize an HttpWebRequest for the current URL. 
        Dim webReq = CType(WebRequest.Create(url), HttpWebRequest)
    
        ' Send the request to the Internet resource and wait for 
        ' the response. 
        ' Note: you can't use HttpWebRequest.GetResponse in a Windows Store app. 
        Using response As WebResponse = webReq.GetResponse()
            ' Get the data stream that is associated with the specified URL. 
            Using responseStream As Stream = response.GetResponseStream()
                ' Read the bytes in responseStream and copy them to content.  
                responseStream.CopyTo(content)
            End Using 
        End Using 
    
        ' Return the result as a byte array. 
        Return content.ToArray()
    End Function 
    
    
    Private Sub DisplayResults(url As String, content As Byte())
    
        ' 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. 
        Dim bytes = content.Length
        ' Strip off the "http://". 
        Dim displayURL = url.Replace("http://", "")
        resultsTextBox.Text &= String.Format(vbCrLf & "{0,-58} {1,8}", displayURL, bytes)
    End Sub
    
    private void SumPageSizes()
    {
        // Make a list of web addresses.
        List<string> urlList = SetUpURLList(); 
    
        var total = 0;
        foreach (var url in urlList)
        {
            // GetURLContents returns the contents of url as a byte array. 
            byte[] urlContents = GetURLContents(url);
    
            DisplayResults(url, urlContents);
    
            // Update the total.
            total += urlContents.Length;
        }
    
        // Display the total count for all of the web addresses.
        resultsTextBox.Text += 
            string.Format("\r\n\r\nTotal bytes returned:  {0}\r\n", total);
    }
    
    
    private List<string> SetUpURLList()
    {
        var urls = new List<string> 
        { 
            "https://msdn.microsoft.com/library/windows/apps/br211380.aspx",
            "https://msdn.microsoft.com",
            "https://msdn.microsoft.com/en-us/library/hh290136.aspx",
            "https://msdn.microsoft.com/en-us/library/ee256749.aspx",
            "https://msdn.microsoft.com/en-us/library/hh290138.aspx",
            "https://msdn.microsoft.com/en-us/library/hh290140.aspx",
            "https://msdn.microsoft.com/en-us/library/dd470362.aspx",
            "https://msdn.microsoft.com/en-us/library/aa578028.aspx",
            "https://msdn.microsoft.com/en-us/library/ms404677.aspx",
            "https://msdn.microsoft.com/en-us/library/ff730837.aspx"
        };
        return urls;
    }
    
    
    private byte[] GetURLContents(string url)
    {
        // The downloaded resource ends up in the variable named content. 
        var content = new MemoryStream();
    
        // Initialize an HttpWebRequest for the current URL. 
        var webReq = (HttpWebRequest)WebRequest.Create(url);
    
        // Send the request to the Internet resource and wait for 
        // the response. 
        // Note: you can't use HttpWebRequest.GetResponse in a Windows Store app. 
        using (WebResponse response = webReq.GetResponse())
        {
            // Get the data stream that is associated with the specified URL. 
            using (Stream responseStream = response.GetResponseStream())
            {
                // Read the bytes in responseStream and copy them to content.  
                responseStream.CopyTo(content);
            }
        }
    
        // Return the result as a byte array. 
        return content.ToArray();
    }
    
    
    private void DisplayResults(string url, byte[] content)
    {
        // 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. 
        var bytes = content.Length;
        // Strip off the "http://".
        var displayURL = url.Replace("http://", "");
        resultsTextBox.Text += string.Format("\n{0,-58} {1,8}", displayURL, bytes);
    }
    

Pour tester la solution synchrone

  • Choisissez la touche F5 pour exécuter le programme, puis choisissez le bouton Démarrer .

    La sortie similaire à la liste suivante doit s'afficher.

    msdn.microsoft.com/library/windows/apps/br211380.aspx        383832
    msdn.microsoft.com                                            33964
    msdn.microsoft.com/en-us/library/hh290136.aspx               225793
    msdn.microsoft.com/en-us/library/ee256749.aspx               143577
    msdn.microsoft.com/en-us/library/hh290138.aspx               237372
    msdn.microsoft.com/en-us/library/hh290140.aspx               128279
    msdn.microsoft.com/en-us/library/dd470362.aspx               157649
    msdn.microsoft.com/en-us/library/aa578028.aspx               204457
    msdn.microsoft.com/en-us/library/ms404677.aspx               176405
    msdn.microsoft.com/en-us/library/ff730837.aspx               143474
    
    Total bytes returned:  1834802
    
    Control returned to startButton_Click.
    

    Notez que cela prend quelques secondes pour afficher les nombres. Pendant ce temps, le thread d'interface utilisateur est bloqué pendant qu'elle attend que les ressources demandées soient téléchargées. Par conséquent, vous ne pouvez pas déplacer, agrandir, réduire ou même fermer la fenêtre d'affichage après avoir choisi le bouton Démarrer. Ces efforts échouent jusqu'à ce que le nombre d'octets commencent à s´afficher. Si un site Web ne répond pas, vous n'avez aucune indication sur le site qui a échoué. Il est même difficile de stopper l'attente et de fermer le programme.

    Comparez ce comportement au Exemple d'une solution asynchrone.

Pour convertir une méthode asynchrone GetURLContents

  1. Pour convertir la solution synchrones vers une solution asynchrone, le meilleur emplacement pour démarrer est dans GetURLContents car les appels à la méthode GetResponse d' HttpWebRequest et à la méthode CopyTo de Stream sont où l'application accède au Web. Le fichier.NET Framework facilite la conversion en fournissant des versions asynchrones des deux méthodes.

    Pour plus d'informations sur les méthodes utilisées dans GetURLContents, consultez WebRequest.

    Notes

    Lorsque vous suivez les étapes décrites dans cette procédure pas à pas, plusieurs erreurs de compilation s'affichent.Vous pouvez les ignorer et reprendre la procédure pas - à - pas.

    Modifiez la méthode appelée dans la troisième ligne de GetURLContents de GetResponse à la méthode asynchrone basée sur la tâche GetResponseAsync .

    Using response As WebResponse = webReq.GetResponseAsync()
    
    using (WebResponse response = webReq.GetResponseAsync())
    
  2. GetResponseAsync retourne un Task. Dans ce cas, la variable de retour de tâche, TResult , est de type WebResponse. La tâche est une promesse de produire un objet réel WebResponse une fois que les données demandées ont été téléchargées et la tâche a été exécutée jusqu´à l'achèvement.

    Pour récupérer la valeur WebResponse de la tâche, appliquez un opérateur Await (Visual Basic) ou await (C#) à l'appel de GetResponseAsync, comme l'illustre le code suivant.

    Using response As WebResponse = Await webReq.GetResponseAsync()
    
    using (WebResponse response = await webReq.GetResponseAsync())
    

    L'opérateur await interrompt l'exécution de la méthode actuelle, GetURLContents, jusqu'à ce que la tâche attendue soit terminé. Entre-temps, le contrôle retourne à l'appelant de la méthode actuelle. Dans cet exemple, la méthode actuelle est GetURLContents , et l'appelant est SumPageSizes . Lorsque la tâche est terminée, l'objet promis WebResponse est produit lorsque la valeur de la tâche attendue et assigné à la variable response.

    L'instruction précédente peut être séparés dans les deux instructions suivantes pour clarifier ce qui se produit.

    'Dim responseTask As Task(Of WebResponse) = webReq.GetResponseAsync() 
    'Using response As WebResponse = Await responseTask
    
    //Task<WebResponse> responseTask = webReq.GetResponseAsync(); 
    //using (WebResponse response = await responseTask)
    

    L'appel à webReq.GetResponseAsync retourne Task(Of WebResponse) ou Task<WebResponse>. Ensuite un opérateur d'attente est appliqué à la tâche pour récupérer la valeur de WebResponse .

    Si votre méthode async a du travail à effectuer qui ne dépend pas de l'achèvement de la tâche, la méthode peut poursuivre ce travail entre ces deux instructions, après l'appel à la méthode async et avant que l'opérateur d'attente soit appliqué. Pour obtenir des exemples, consultez Comment : effectuer plusieurs requêtes Web en parallèle en utilisant Async et Await (C# et Visual Basic) et Comment : étendre la procédure pas à pas Async à l'aide de Task.WhenAll (C# et Visual Basic).

  3. Étant donné que vous avez ajouté l'opérateur Await ou await dans l'étape précédente, une erreur de compilateur se produit. L'opérateur peut être utilisé uniquement dans les méthodes marquées avec le modificateur Async (Visual Basic) ou async (C#). Ignorer l'erreur alors que vous répétez les étapes de conversion pour remplacer l'appel à CopyTo avec un appel à CopyToAsync .

    • Changer le nom de la méthode qui est appelée pour CopyToAsync.

    • La méthode CopyTo ou CopyToAsync copie les octets à son argument, content et ne retourne pas une valeur significative. Dans la version synchrone, l'appel à CopyTo est une simple instruction qui ne renvoie pas une valeur. La version asynchrone, CopyToAsync , renvoie un Task. Les fonctions de tâche comme « Task(void) » et permet à la méthode d'être attendue. Applique Await ou await à l'appel de CopyToAsync, comme l'illustre le code suivant.

      Await responseStream.CopyToAsync(content)
      
      await responseStream.CopyToAsync(content);
      

      L'instruction précédente abrège les deux lignes de code suivantes.

      ' CopyToAsync returns a Task, not a Task<T>. 
      'Dim copyTask As Task = responseStream.CopyToAsync(content) 
      
      ' When copyTask is completed, content contains a copy of 
      ' responseStream. 
      'Await copyTask
      
      // CopyToAsync returns a Task, not a Task<T>. 
      //Task copyTask = responseStream.CopyToAsync(content); 
      
      // When copyTask is completed, content contains a copy of 
      // responseStream. 
      //await copyTask;
      
  4. Il ne reste à qu´`a ajuster la signature de méthode dans GetURLContents. Vous pouvez utiliser l'opérateur Await ou awaituniquement dans les méthodes marquées avec le modificateur Async (Visual Basic) ou async (C#). Ajoutez le modificateur pour marquer la méthode comme méthode async, comme l'illustre le code suivant.

    Private Async Function GetURLContents(url As String) As Byte()
    
    private async byte[] GetURLContents(string url)
    
  5. Le type de retour d'une méthode async peut être Task, Task, ou void en C#. En Visual Basic, la méthode doit être une Function qui renvoie une Task ou un Task(Of T) , ou la méthode doit être un Sub . En général, une méthode Sub (Visual Basic) ou un type de retour void (C#) est utilisée uniquement dans un gestionnaire d'événements async, où Sub ou void est requis. Dans les autres cas, vous utilisez Task(T) si la méthode terminée a une instruction Return ou return qui renvoie une valeur de type T, et que vous utilisez Task si la méthode terminée ne retourne pas une valeur significative. Vous pouvez considérer le type de retour Task comme signification « Task(void) ».

    Pour plus d'informations, consultez Types de retour Async (C# et Visual Basic).

    Méthode GetURLContents a une instruction return, et l'instruction renvoie un tableau d'octets. Par conséquent, le type de retour de la version asynchrone est Task(T), où T est un tableau d'octets. Apportez les modifications suivantes à la méthode de signature:

    • Modifiez le type de retour par Task(Of Byte()) (Visual Basic) ou Task<byte[]> (C#).

    • Par convention, les méthodes asynchrones ont des noms qui se terminent par « Async », par conséquent, renommez la méthode GetURLContentsAsync .

    Le code suivant montre ces changements.

    Private Async Function GetURLContentsAsync(url As String) As Task(Of Byte())
    
    private async Task<byte[]> GetURLContentsAsync(string url)
    

    Avec ces quelques modifications, la conversion de GetURLContents en une méthode asynchrone est terminée.

Pour convertir une méthode asynchrone SumPageSizes

  1. Répétez les étapes de la procédure précédente pour SumPageSizes . D'abord, remplacez l'appel à GetURLContents par un appel asynchrone.

    • Modifier le nom de la méthode qui est appelée à partir de GetURLContents en GetURLContentsAsync , si vous ne l´avez pas déjà fait.

    • Appliquez Await ou await à la tâche que GetURLContentsAsync retourne pour obtenir la valeur du tableau d'octets.

    Le code suivant montre ces changements.

    Dim urlContents As Byte() = Await GetURLContentsAsync(url)
    
    byte[] urlContents = await GetURLContentsAsync(url);
    

    L'assignation précédente abrège les deux lignes de code suivantes.

    ' GetURLContentsAsync returns a task. At completion, the task 
    ' produces a byte array. 
    'Dim getContentsTask As Task(Of Byte()) = GetURLContentsAsync(url) 
    'Dim urlContents As Byte() = Await getContentsTask
    
    // GetURLContentsAsync returns a Task<T>. At completion, the task 
    // produces a byte array. 
    //Task<byte[]> getContentsTask = GetURLContentsAsync(url); 
    //byte[] urlContents = await getContentsTask;
    
  2. Apportez les modifications suivantes à la signature de la méthode:

    • Marquez la méthode avec le modificateur Async ou async .

    • Ajoutez « Async » au nom de la méthode.

    • Il n´existe aucune variable de retour de tâche, T, cette fois-ci, car SumPageSizesAsync ne renvoie pas une valeur de T. (La méthode n'a pas d'instruction Return ou return ) Toutefois, la méthode doit retourner un Task pour être awaitable. Par conséquent, effectuez l'une des modifications suivantes :

      • En Visual Basic, remplacez le type de méthode Sub par Function. Le type de retour de la fonction est Task.

      • En C#, remplacez le type de retour de la méthode de void à Task.

    Le code suivant montre ces changements.

    Private Async Function SumPageSizesAsync() As Task
    
    private async Task SumPageSizesAsync()
    

    La conversion de SumPageSizes à SumPageSizesAsync est terminée.

Pour convertir startButton_Click en une méthode asynchrone

  1. Dans le gestionnaire d'événements, modifiez le nom de la méthode appelée SumPageSizes par SumPageSizesAsync, si ce n'est déjà fait.

  2. Étant donné que SumPageSizesAsync est une méthode async, remplacez le code du gestionnaire d'événements pour attendre le résultat.

    L'appel à SumPageSizesAsync reflète l'appel à CopyToAsync dans GetURLContentsAsync . L'appel retourne un Task , et non pas un Task(T) .

    Comme dans les procédures précédentes, vous pouvez convertir l'appel à l'aide d'une seule ou de deux instructions. Le code suivant montre ces changements.

    '' One-step async call.
    Await SumPageSizesAsync()
    
    ' Two-step async call. 
    'Dim sumTask As Task = SumPageSizesAsync() 
    'Await sumTask
    
    // One-step async call.
    await SumPageSizesAsync();
    
    // Two-step async call. 
    //Task sumTask = SumPageSizesAsync(); 
    //await sumTask;
    
  3. Pour empêcher entrer à nouveau par erreur l'exécution, ajoutez l'instruction suivante au début d' startButton_Click pour désactiver le bouton Démarrer .

    ' Disable the button until the operation is complete.
    startButton.IsEnabled = False
    
    // Disable the button until the operation is complete.
    startButton.IsEnabled = false;
    

    Vous pouvez permettre à nouveau sur le bouton à la fin de le gestionnaire d'événements.

    ' Reenable the button in case you want to run the operation again.
    startButton.IsEnabled = True
    
    // Reenable the button in case you want to run the operation again.
    startButton.IsEnabled = true;
    

    Pour plus d'informations sur la réentrance, consultez Gestion de la réentrance dans Async Apps (C# et Visual Basic).

  4. Enfin, ajoutez le modificateur Async ou async à la déclaration afin que le gestionnaire d'événements puisse attendre SumPagSizesAsync.

    Async Sub startButton_Click(sender As Object, e As RoutedEventArgs) Handles startButton.Click
    
    private async void startButton_Click(object sender, RoutedEventArgs e)
    

    En règle générale, les noms des gestionnaires d'événements ne sont pas modifiées. Le type de retour n'est pas modifié à Task car les gestionnaires d'événements doivent retourner void en C# ou être des procédures Sub en Visual Basic. Par conséquent, le type à retourner Task.

    La conversion du projet de traitement sw synchrone à asynchrone est terminée.

Pour tester la solution asynchrone

  1. Choisissez la touche F5 pour exécuter le programme, puis choisissez le bouton Démarrer .

  2. La sortie similaire à la sortie de la solution synchrone doit s'afficher. Toutefois, remarquez les différences suivantes :

    • Les résultats ne se produisent en même temps, une fois le traitement terminé. Par exemple, les deux programmes contiennent une ligne startButton_Click qui efface la zone de texte. L'objectif est de supprimer la zone de texte entre les exécutions si vous choisissez le bouton Démarrer une deuxième fois, après qu´un ensemble de résultats soit apparu. Dans la version synchrone, la zone de texte est supprimée juste avant que les nombres s'affichent pour la deuxième fois, lorsque les téléchargements sont terminés et que le thread d'interface utilisateur est libre pour effectuer d'autres tâches. Dans la version asynchrone, la zone de texte supprime immédiatement le contenu après que vous ayez choisi le bouton Démarrer .

    • Avant tout, le thread d'interface utilisateur n'est pas bloqué pendant les téléchargements. Vous pouvez déplacer ou redimensionner la fenêtre pendant que les ressources web sont téléchargées, comptées, et affichées. Si l'un des sites Web est lent ou ne répond pas, vous pouvez annuler l'opération en cliquant sur le bouton Fermer ( la croix dans le champ rouge dans l'angle supérieur droit).

Pour remplacer la méthode GetURLContentsAsync avec une méthode du .NET Framework

  1. Le .NET Framework 4,5 fournit de nombreuses méthodes async que vous pouvez utiliser. L'une d'elles, la méthode HttpClient de GetByteArrayAsync(String) , effectue uniquement ce dont vous avez besoin pour cette procédure pas - à - pas. Vous pouvez l'utiliser au lieu de la méthode GetURLContentsAsync que vous avez créée dans la première procédure.

    La première étape consiste à créer un objet HttpClient dans la méthode SumPageSizesAsync . Au début de la méthode , ajoutez la déclaration suivante.

    ' Declare an HttpClient object and increase the buffer size. The 
    ' default buffer size is 65,536. 
    Dim client As HttpClient =
        New HttpClient() With {.MaxResponseContentBufferSize = 1000000}
    
    // Declare an HttpClient object and increase the buffer size. The 
    // default buffer size is 65,536.
    HttpClient client =
        new HttpClient() { MaxResponseContentBufferSize = 1000000 };
    
  2. Dans SumPageSizesAsync, remplacez l´appel à la méthode GetURLContentsAsync avec un appel à la méthode HttpClient.

    Dim urlContents As Byte() = Await client.GetByteArrayAsync(url)
    
    byte[] urlContents = await client.GetByteArrayAsync(url);               
    
  3. Supprimez ou mettez en commentaire la méthode GetURLContentsAsync que vous avez écrit.

  4. Choisissez la touche F5 pour exécuter le programme, puis choisissez le bouton Démarrer .

    Le comportement de cette version du projet doit correspondre au comportement que la procédure « pour tester la solution asynchrone » décrit mais avec encore moins d'efforts de votre part.

Exemple

Le code suivant contient l'exemple complet de la conversion d'une solution synchrones vers une solution asynchrone à l'aide de la méthode asynchrone de GetURLContentsAsync que vous avez entrée. Notez qu'elle ressemble fortement à la solution synchrone d'origine.

' Add the following Imports statements, and add a reference for System.Net.Http. 
Imports System.Net.Http
Imports System.Net
Imports System.IO

Class MainWindow

    Async Sub startButton_Click(sender As Object, e As RoutedEventArgs) Handles startButton.Click

        ' Disable the button until the operation is complete.
        startButton.IsEnabled = False

        resultsTextBox.Clear()

        '' One-step async call.
        Await SumPageSizesAsync()

        ' Two-step async call. 
        'Dim sumTask As Task = SumPageSizesAsync() 
        'Await sumTask

        resultsTextBox.Text &= vbCrLf & "Control returned to button1_Click." 

        ' Reenable the button in case you want to run the operation again.
        startButton.IsEnabled = True 
    End Sub 


    Private Async Function SumPageSizesAsync() As Task

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

        Dim total = 0
        For Each url In urlList
            Dim urlContents As Byte() = Await GetURLContentsAsync(url)

            ' The previous line abbreviates the following two assignment statements. 

            ' GetURLContentsAsync returns a task. At completion, the task 
            ' produces a byte array. 
            'Dim getContentsTask As Task(Of Byte()) = GetURLContentsAsync(url) 
            'Dim urlContents As Byte() = Await getContentsTask

            DisplayResults(url, urlContents)

            ' 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:  {0}" & vbCrLf, total)
    End Function 


    Private Function SetUpURLList() As List(Of String)

        Dim urls = New List(Of String) From
            {
                "https://msdn.microsoft.com/library/windows/apps/br211380.aspx",
                "https://msdn.microsoft.com",
                "https://msdn.microsoft.com/en-us/library/hh290136.aspx",
                "https://msdn.microsoft.com/en-us/library/ee256749.aspx",
                "https://msdn.microsoft.com/en-us/library/hh290138.aspx",
                "https://msdn.microsoft.com/en-us/library/hh290140.aspx",
                "https://msdn.microsoft.com/en-us/library/dd470362.aspx",
                "https://msdn.microsoft.com/en-us/library/aa578028.aspx",
                "https://msdn.microsoft.com/en-us/library/ms404677.aspx",
                "https://msdn.microsoft.com/en-us/library/ff730837.aspx"
            }
        Return urls
    End Function 


    Private Async Function GetURLContentsAsync(url As String) As Task(Of Byte())

        ' The downloaded resource ends up in the variable named content. 
        Dim content = New MemoryStream()

        ' Initialize an HttpWebRequest for the current URL. 
        Dim webReq = CType(WebRequest.Create(url), HttpWebRequest)

        ' Send the request to the Internet resource and wait for 
        ' the response. 
        Using response As WebResponse = Await webReq.GetResponseAsync()

            ' The previous statement abbreviates the following two statements. 

            'Dim responseTask As Task(Of WebResponse) = webReq.GetResponseAsync() 
            'Using response As WebResponse = Await responseTask 

            ' Get the data stream that is associated with the specified URL. 
            Using responseStream As Stream = response.GetResponseStream()
                ' Read the bytes in responseStream and copy them to content.  
                Await responseStream.CopyToAsync(content)

                ' The previous statement abbreviates the following two statements. 

                ' CopyToAsync returns a Task, not a Task<T>. 
                'Dim copyTask As Task = responseStream.CopyToAsync(content) 

                ' When copyTask is completed, content contains a copy of 
                ' responseStream. 
                'Await copyTask 
            End Using 
        End Using 

        ' Return the result as a byte array. 
        Return content.ToArray()
    End Function 


    Private Sub DisplayResults(url As String, content As Byte())

        ' 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. 
        Dim bytes = content.Length
        ' Strip off the "http://". 
        Dim displayURL = url.Replace("http://", "")
        resultsTextBox.Text &= String.Format(vbCrLf & "{0,-58} {1,8}", displayURL, bytes)
    End Sub 

End Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

// Add the following using directives, and add a reference for System.Net.Http. 
using System.Net.Http;
using System.IO;
using System.Net;

namespace AsyncExampleWPF
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void startButton_Click(object sender, RoutedEventArgs e)
        {
            // Disable the button until the operation is complete.
            startButton.IsEnabled = false;

            resultsTextBox.Clear();

            // One-step async call.
            await SumPageSizesAsync();

            // Two-step async call. 
            //Task sumTask = SumPageSizesAsync(); 
            //await sumTask;

            resultsTextBox.Text += "\r\nControl returned to startButton_Click.\r\n";

            // Reenable the button in case you want to run the operation again.
            startButton.IsEnabled = true;
        }


        private async Task SumPageSizesAsync()
        {
            // Make a list of web addresses.
            List<string> urlList = SetUpURLList();

            var total = 0;

            foreach (var url in urlList)
            {
                byte[] urlContents = await GetURLContentsAsync(url);

                // The previous line abbreviates the following two assignment statements. 

                // GetURLContentsAsync returns a Task<T>. At completion, the task 
                // produces a byte array. 
                //Task<byte[]> getContentsTask = GetURLContentsAsync(url); 
                //byte[] urlContents = await getContentsTask;

                DisplayResults(url, urlContents);

                // Update the total.          
                total += urlContents.Length;
            }
            // Display the total count for all of the websites.
            resultsTextBox.Text +=
                string.Format("\r\n\r\nTotal bytes returned:  {0}\r\n", total);
        }


        private List<string> SetUpURLList()
        {
            List<string> urls = new List<string> 
            { 
                "https://msdn.microsoft.com/library/windows/apps/br211380.aspx",
                "https://msdn.microsoft.com",
                "https://msdn.microsoft.com/en-us/library/hh290136.aspx",
                "https://msdn.microsoft.com/en-us/library/ee256749.aspx",
                "https://msdn.microsoft.com/en-us/library/hh290138.aspx",
                "https://msdn.microsoft.com/en-us/library/hh290140.aspx",
                "https://msdn.microsoft.com/en-us/library/dd470362.aspx",
                "https://msdn.microsoft.com/en-us/library/aa578028.aspx",
                "https://msdn.microsoft.com/en-us/library/ms404677.aspx",
                "https://msdn.microsoft.com/en-us/library/ff730837.aspx"
            };
            return urls;
        }


        private async Task<byte[]> GetURLContentsAsync(string url)
        {
            // The downloaded resource ends up in the variable named content. 
            var content = new MemoryStream();

            // Initialize an HttpWebRequest for the current URL. 
            var webReq = (HttpWebRequest)WebRequest.Create(url);

            // Send the request to the Internet resource and wait for 
            // the response.                 
            using (WebResponse response = await webReq.GetResponseAsync())

            // The previous statement abbreviates the following two statements. 

            //Task<WebResponse> responseTask = webReq.GetResponseAsync(); 
            //using (WebResponse response = await responseTask)
            {
                // Get the data stream that is associated with the specified url. 
                using (Stream responseStream = response.GetResponseStream())
                {
                    // Read the bytes in responseStream and copy them to content. 
                    await responseStream.CopyToAsync(content);

                    // The previous statement abbreviates the following two statements. 

                    // CopyToAsync returns a Task, not a Task<T>. 
                    //Task copyTask = responseStream.CopyToAsync(content); 

                    // When copyTask is completed, content contains a copy of 
                    // responseStream. 
                    //await copyTask;
                }
            }
            // Return the result as a byte array. 
            return content.ToArray();
        }


        private void DisplayResults(string url, byte[] content)
        {
            // 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. 
            var bytes = content.Length;
            // Strip off the "http://".
            var displayURL = url.Replace("http://", "");
            resultsTextBox.Text += string.Format("\n{0,-58} {1,8}", displayURL, bytes);
        }
    }
}

Le code suivant contient l'exemple complet de la solution utilisant la méthode HttpClient , GetByteArrayAsync.

' Add the following Imports statements, and add a reference for System.Net.Http. 
Imports System.Net.Http
Imports System.Net
Imports System.IO

Class MainWindow

    Async Sub startButton_Click(sender As Object, e As RoutedEventArgs) Handles startButton.Click

        resultsTextBox.Clear()

        ' Disable the button until the operation is complete.
        startButton.IsEnabled = False 

        ' One-step async call.
        Await SumPageSizesAsync()

        '' Two-step async call. 
        'Dim sumTask As Task = SumPageSizesAsync() 
        'Await sumTask

        resultsTextBox.Text &= vbCrLf & "Control returned to button1_Click." 

        ' Reenable the button in case you want to run the operation again.
        startButton.IsEnabled = True 
    End Sub 


    Private Async Function SumPageSizesAsync() As Task

        ' Declare an HttpClient object and increase the buffer size. The 
        ' default buffer size is 65,536. 
        Dim client As HttpClient =
            New HttpClient() With {.MaxResponseContentBufferSize = 1000000}

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

        Dim total = 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)

            ' The following two lines can replace the previous assignment statement. 
            'Dim getContentsTask As Task(Of Byte()) = client.GetByteArrayAsync(url) 
            'Dim urlContents As Byte() = Await getContentsTask

            DisplayResults(url, urlContents)

            ' 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:  {0}" & vbCrLf, total)
    End Function 


    Private Function SetUpURLList() As List(Of String)

        Dim urls = New List(Of String) From
            {
                "https://msdn.microsoft.com/library/windows/apps/br211380.aspx",
                "https://msdn.microsoft.com",
                "https://msdn.microsoft.com/en-us/library/hh290136.aspx",
                "https://msdn.microsoft.com/en-us/library/ee256749.aspx",
                "https://msdn.microsoft.com/en-us/library/hh290138.aspx",
                "https://msdn.microsoft.com/en-us/library/hh290140.aspx",
                "https://msdn.microsoft.com/en-us/library/dd470362.aspx",
                "https://msdn.microsoft.com/en-us/library/aa578028.aspx",
                "https://msdn.microsoft.com/en-us/library/ms404677.aspx",
                "https://msdn.microsoft.com/en-us/library/ff730837.aspx"
            }
        Return urls
    End Function 


    Private Sub DisplayResults(url As String, content As Byte())

        ' 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. 
        Dim bytes = content.Length
        ' Strip off the "http://". 
        Dim displayURL = url.Replace("http://", "")
        resultsTextBox.Text &= String.Format(vbCrLf & "{0,-58} {1,8}", displayURL, bytes)
    End Sub 

End Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

// Add the following using directives, and add a reference for System.Net.Http. 
using System.Net.Http;
using System.IO;
using System.Net;


namespace AsyncExampleWPF
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void startButton_Click(object sender, RoutedEventArgs e)
        {
            resultsTextBox.Clear();

            // Disable the button until the operation is complete.
            startButton.IsEnabled = false;

            // One-step async call.
            await SumPageSizesAsync();

            //// Two-step async call. 
            //Task sumTask = SumPageSizesAsync(); 
            //await sumTask;

            resultsTextBox.Text += "\r\nControl returned to startButton_Click.\r\n";

            // Reenable the button in case you want to run the operation again.
            startButton.IsEnabled = true;
        }


        private async Task SumPageSizesAsync()
        {
            // Declare an HttpClient object and increase the buffer size. The 
            // default buffer size is 65,536.
            HttpClient client =
                new HttpClient() { MaxResponseContentBufferSize = 1000000 };

            // Make a list of web addresses.
            List<string> urlList = SetUpURLList();

            var total = 0;

            foreach (var url in urlList)
            {
                // GetByteArrayAsync returns a task. At completion, the task 
                // produces a byte array. 
                byte[] urlContents = await client.GetByteArrayAsync(url);               

                // The following two lines can replace the previous assignment statement. 
                //Task<byte[]> getContentsTask = client.GetByteArrayAsync(url); 
                //byte[] urlContents = await getContentsTask;

                DisplayResults(url, urlContents);

                // Update the total.
                total += urlContents.Length;
            }

            // Display the total count for all of the websites.
            resultsTextBox.Text +=
                string.Format("\r\n\r\nTotal bytes returned:  {0}\r\n", total);
        }


        private List<string> SetUpURLList()
        {
            List<string> urls = new List<string> 
            { 
                "https://msdn.microsoft.com/library/windows/apps/br211380.aspx",
                "https://msdn.microsoft.com",
                "https://msdn.microsoft.com/en-us/library/hh290136.aspx",
                "https://msdn.microsoft.com/en-us/library/ee256749.aspx",
                "https://msdn.microsoft.com/en-us/library/hh290138.aspx",
                "https://msdn.microsoft.com/en-us/library/hh290140.aspx",
                "https://msdn.microsoft.com/en-us/library/dd470362.aspx",
                "https://msdn.microsoft.com/en-us/library/aa578028.aspx",
                "https://msdn.microsoft.com/en-us/library/ms404677.aspx",
                "https://msdn.microsoft.com/en-us/library/ff730837.aspx"
            };
            return urls;
        }


        private void DisplayResults(string url, byte[] content)
        {
            // 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. 
            var bytes = content.Length;
            // Strip off the "http://".
            var displayURL = url.Replace("http://", "");
            resultsTextBox.Text += string.Format("\n{0,-58} {1,8}", displayURL, bytes);
        }
    }
}

Voir aussi

Tâches

Comment : étendre la procédure pas à pas Async à l'aide de Task.WhenAll (C# et Visual Basic)

Comment : effectuer plusieurs requêtes Web en parallèle en utilisant Async et Await (C# et Visual Basic)

Procédure pas à pas : utilisation du débogueur avec les méthodes Async

Référence

async (référence C#)

await (Référence C#)

Await, opérateur (Visual Basic)

Async (Visual Basic)

Concepts

Programmation asynchrone avec Async et Await (C# et Visual Basic)

Types de retour Async (C# et Visual Basic)

Utiliser Async pour l'accès aux fichiers (C# et Visual Basic)

Autres ressources

Exemple Async : Accès à la procédure Web (C# et Visual Basic)

programmation asynchrone basé sur la tâche (TAP)

Démarrage rapide : à l'aide de l'opérateur await pour la programmation asynchrone