Przewodnik: uzyskiwanie dostępu do sieci Web za pomocą AsyncC#i Await ()Walkthrough: Accessing the Web by Using async and await (C#)

Można łatwiej pisać programy asynchroniczne i intuicyjnie przy użyciu funkcji asynchronicznych/await.You can write asynchronous programs more easily and intuitively by using async/await features. Można napisać kod asynchroniczny, który wygląda podobnie do kodu synchronicznego i pozwolić kompilatorowi obsłużyć trudne funkcje wywołania zwrotnego i kontynuację, która zwykle wiąże się z kodem asynchronicznym.You can write asynchronous code that looks like synchronous code and let the compiler handle the difficult callback functions and continuations that asynchronous code usually entails.

Aby uzyskać więcej informacji o funkcji asynchronicznej, zobacz programowanie asynchroniczne z Async i awaitC#().For more information about the Async feature, see Asynchronous Programming with async and await (C#).

Ten Instruktaż rozpoczyna się od synchronicznej aplikacji Windows Presentation Foundation (WPF), która sumuje liczbę bajtów na liście witryn sieci Web.This walkthrough starts with a synchronous Windows Presentation Foundation (WPF) application that sums the number of bytes in a list of websites. Następnie Instruktaż konwertuje aplikację na rozwiązanie asynchroniczne przy użyciu nowych funkcji.The walkthrough then converts the application to an asynchronous solution by using the new features.

Jeśli nie chcesz samodzielnie kompilować aplikacji, możesz pobrać próbkę asynchroniczną: uzyskiwanie dostępu do przewodnika sieciC# Web (i Visual Basic).If you don't want to build the applications yourself, you can download Async Sample: Accessing the Web Walkthrough (C# and Visual Basic).

Uwaga

Aby uruchomić przykłady, musisz mieć zainstalowany na komputerze program Visual Studio 2012 lub nowszy oraz .NET Framework 4,5 lub nowszy.To run the examples, you must have Visual Studio 2012 or newer and the .NET Framework 4.5 or newer installed on your computer.

Tworzenie aplikacji WPFCreate a WPF application

  1. Uruchom program Visual Studio.Start Visual Studio.

  2. Na pasku menu wybierz kolejno pozycje plik > Nowy > projekt.On the menu bar, choose File > New > Project.

    Zostanie otwarte okno dialogowe Nowy projekt .The New Project dialog box opens.

  3. W okienku zainstalowane szablony wybierz pozycję Wizualizacja C#, a następnie wybierz pozycję Aplikacja WPF z listy typów projektów.In the Installed Templates pane, choose Visual C#, and then choose WPF Application from the list of project types.

  4. W polu tekstowym Nazwa wprowadź AsyncExampleWPF, a następnie wybierz przycisk OK .In the Name text box, enter AsyncExampleWPF, and then choose the OK button.

    Nowy projekt zostanie wyświetlony w Eksplorator rozwiązań.The new project appears in Solution Explorer.

Projektowanie prostego MainWindow WPFDesign a simple WPF MainWindow

  1. W edytorze Visual Studio Code wybierz kartę MainWindow. XAML .In the Visual Studio Code Editor, choose the MainWindow.xaml tab.

  2. Jeśli okno Przybornik nie jest widoczne, otwórz menu Widok , a następnie wybierz Przybornik.If the Toolbox window isn’t visible, open the View menu, and then choose Toolbox.

  3. Dodaj kontrolkę przycisk i kontrolkę TextBox do okna MainWindow .Add a Button control and a TextBox control to the MainWindow window.

  4. Zaznacz kontrolkę TextBox , a następnie w oknie Właściwości ustaw następujące wartości:Highlight the TextBox control and, in the Properties window, set the following values:

    • Ustaw właściwość name na resultsTextBox.Set the Name property to resultsTextBox.

    • Ustaw właściwość Height na 250.Set the Height property to 250.

    • Ustaw właściwość Width na 500.Set the Width property to 500.

    • Na karcie tekst Określ czcionkę o stałej szerokości, taką jak Lucida Console lub globalne.On the Text tab, specify a monospaced font, such as Lucida Console or Global Monospace.

  5. Zaznacz kontrolkę przycisk , a następnie w oknie Właściwości ustaw następujące wartości:Highlight the Button control and, in the Properties window, set the following values:

    • Ustaw właściwość name na startButton.Set the Name property to startButton.

    • Zmień wartość właściwości zawartości z przycisku na Rozpocznij.Change the value of the Content property from Button to Start.

  6. Umieść pole tekstowe i przycisk tak, aby oba elementy pojawiły się w oknie MainWindow .Position the text box and the button so that both appear in the MainWindow window.

    Aby uzyskać więcej informacji na temat projektant XAML WPF, zobacz Tworzenie interfejsu użytkownika przy użyciu Projektant XAML.For more information about the WPF XAML Designer, see Creating a UI by using XAML Designer.

Dodaj odwołanieAdd a reference

  1. W Eksplorator rozwiązańzaznacz nazwę projektu.In Solution Explorer, highlight your project's name.

  2. Na pasku menu wybierz projekt > Dodaj odwołanie.On the menu bar, choose Project > Add Reference.

    Zostanie wyświetlone okno dialogowe Menedżer odwołań .The Reference Manager dialog box appears.

  3. W górnej części okna dialogowego upewnij się, że projekt ma wartość docelową .NET Framework 4,5 lub wyższą.At the top of the dialog box, verify that your project is targeting the .NET Framework 4.5 or higher.

  4. W kategorii zestawy wybierz pozycję Struktura , jeśli nie została jeszcze wybrana.In the Assemblies category, choose Framework if it isn’t already chosen.

  5. Na liście nazw, zaznacz pole wyboru System .NET. http .In the list of names, select the System.Net.Http check box.

  6. Wybierz przycisk OK , aby zamknąć okno dialogowe.Choose the OK button to close the dialog box.

Dodaj wymagane dyrektywy usingAdd necessary using directives

  1. W Eksplorator rozwiązańOtwórz menu skrótów dla MainWindow.XAML.cs, a następnie wybierz polecenie Wyświetl kod.In Solution Explorer, open the shortcut menu for MainWindow.xaml.cs, and then choose View Code.

  2. Dodaj następujące dyrektywy using w górnej części pliku kodu, jeśli jeszcze nie istnieją.Add the following using directives at the top of the code file if they’re not already present.

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

Tworzenie aplikacji synchronicznejCreate a synchronous app

  1. W oknie projekt MainWindow. XAML kliknij dwukrotnie przycisk Start , aby utworzyć procedurę obsługi zdarzeń startButton_Click w MainWindow.XAML.cs.In the design window, MainWindow.xaml, double-click the Start button to create the startButton_Click event handler in MainWindow.xaml.cs.

  2. W MainWindow.xaml.cs Skopiuj następujący kod do treści startButton_Click:In MainWindow.xaml.cs, copy the following code into the body of startButton_Click:

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

    Kod wywołuje metodę, która dysków aplikacji, SumPageSizesi wyświetla komunikat, gdy sterowanie powraca do startButton_Click.The code calls the method that drives the application, SumPageSizes, and displays a message when control returns to startButton_Click.

  3. Kod rozwiązania synchronicznego zawiera następujące cztery metody:The code for the synchronous solution contains the following four methods:

    • SumPageSizes, który pobiera listę adresów URL stron sieci Web z SetUpURLList, a następnie wywołuje GetURLContents i DisplayResults do przetwarzania każdego adresu URL.SumPageSizes, which gets a list of webpage URLs from SetUpURLList and then calls GetURLContents and DisplayResults to process each URL.

    • SetUpURLList, co umożliwia i zwraca listę adresów sieci Web.SetUpURLList, which makes and returns a list of web addresses.

    • GetURLContents, która pobiera zawartość każdej witryny sieci Web i zwraca zawartość jako tablicę bajtów.GetURLContents, which downloads the contents of each website and returns the contents as a byte array.

    • DisplayResults, która wyświetla liczbę bajtów w tablicy bajtowej dla każdego adresu URL.DisplayResults, which displays the number of bytes in the byte array for each URL.

    Skopiuj poniższe cztery metody, a następnie wklej je w ramach procedury obsługi zdarzeń startButton_Click w MainWindow.xaml.cs:Copy the following four methods, and then paste them under the startButton_Click event handler in MainWindow.xaml.cs:

    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 += $"\r\n\r\nTotal bytes returned:  {total}\r\n";
    }
    
    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/library/hh290136.aspx",
            "https://msdn.microsoft.com/library/ee256749.aspx",
            "https://msdn.microsoft.com/library/hh290138.aspx",
            "https://msdn.microsoft.com/library/hh290140.aspx",
            "https://msdn.microsoft.com/library/dd470362.aspx",
            "https://msdn.microsoft.com/library/aa578028.aspx",
            "https://msdn.microsoft.com/library/ms404677.aspx",
            "https://msdn.microsoft.com/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 "https://".
        var displayURL = url.Replace("https://", "");
        resultsTextBox.Text += $"\n{displayURL,-58} {bytes,8}";
    }
    

Testowanie rozwiązania synchronicznegoTest the synchronous solution

Wybierz klawisz F5 , aby uruchomić program, a następnie wybierz przycisk Start .Choose the F5 key to run the program, and then choose the Start button.

Powinny pojawić się dane wyjściowe podobne do poniższej listy:Output that resembles the following list should appear:

msdn.microsoft.com/library/windows/apps/br211380.aspx        383832
msdn.microsoft.com                                            33964
msdn.microsoft.com/library/hh290136.aspx               225793
msdn.microsoft.com/library/ee256749.aspx               143577
msdn.microsoft.com/library/hh290138.aspx               237372
msdn.microsoft.com/library/hh290140.aspx               128279
msdn.microsoft.com/library/dd470362.aspx               157649
msdn.microsoft.com/library/aa578028.aspx               204457
msdn.microsoft.com/library/ms404677.aspx               176405
msdn.microsoft.com/library/ff730837.aspx               143474

Total bytes returned:  1834802

Control returned to startButton_Click.

Należy zauważyć, że wyświetlanie liczników zajmuje kilka sekund.Notice that it takes a few seconds to display the counts. W tym czasie wątek interfejsu użytkownika jest blokowany podczas oczekiwania na pobranie żądanych zasobów.During that time, the UI thread is blocked while it waits for requested resources to download. W związku z tym nie można przenieść, zmaksymalizować ani zminimalizować, a nawet zamknąć okno wyświetlania po wybraniu przycisku Rozpocznij .As a result, you can't move, maximize, minimize, or even close the display window after you choose the Start button. Te działania kończą się niepowodzeniem, dopóki liczba bajtów nie zostanie wyświetlona.These efforts fail until the byte counts start to appear. Jeśli witryna sieci Web nie odpowiada, nie ma informacji o tym, która lokacja nie powiodła się.If a website isn’t responding, you have no indication of which site failed. Trudno jest nawet przestać czekać i zamknąć program.It is difficult even to stop waiting and close the program.

Konwertuj GetURLContents na metodę asynchronicznąConvert GetURLContents to an asynchronous method

  1. Aby przekonwertować rozwiązanie synchroniczne na rozwiązanie asynchroniczne, najlepszym miejscem do uruchomienia jest w GetURLContents, ponieważ wywołania metody HttpWebRequest GetResponse oraz do metody Stream CopyTo to miejsce, w którym aplikacja uzyskuje dostęp do sieci Web.To convert the synchronous solution to an asynchronous solution, the best place to start is in GetURLContents because the calls to the HttpWebRequest method GetResponse and to the Stream method CopyTo are where the application accesses the web. .NET Framework ułatwia konwersję, dostarczając asynchroniczną wersję obu tych metod.The .NET Framework makes the conversion easy by supplying asynchronous versions of both methods.

    Aby uzyskać więcej informacji na temat metod, które są używane w GetURLContents, zobacz WebRequest.For more information about the methods that are used in GetURLContents, see WebRequest.

    Uwaga

    Po wykonaniu kroków opisanych w tym instruktażu wyświetlane są kilka błędów kompilatora.As you follow the steps in this walkthrough, several compiler errors appear. Można je zignorować i kontynuować z przewodnikiem.You can ignore them and continue with the walkthrough.

    Zmień metodę, która jest wywoływana w trzecim wierszu GetURLContents z GetResponse do asynchronicznej metody GetResponseAsync opartej na zadaniach.Change the method that's called in the third line of GetURLContents from GetResponse to the asynchronous, task-based GetResponseAsync method.

    using (WebResponse response = webReq.GetResponseAsync())
    
  2. GetResponseAsync zwraca Task<TResult>.GetResponseAsync returns a Task<TResult>. W takim przypadku zmienna zwracająca zadanie, TResult, ma typ WebResponse.In this case, the task return variable, TResult, has type WebResponse. Zadanie to obietnica do utworzenia rzeczywistego obiektu WebResponse po pobraniu żądanych danych, a zadanie zostało wykonane w celu ukończenia.The task is a promise to produce an actual WebResponse object after the requested data has been downloaded and the task has run to completion.

    Aby pobrać wartość WebResponse z zadania, Zastosuj operator await do wywołania GetResponseAsync, jak pokazano w poniższym kodzie.To retrieve the WebResponse value from the task, apply an await operator to the call to GetResponseAsync, as the following code shows.

    using (WebResponse response = await webReq.GetResponseAsync())
    

    Operator await zawiesza wykonywanie bieżącej metody, GetURLContents, dopóki zadanie nie zostanie ukończone.The await operator suspends the execution of the current method, GetURLContents, until the awaited task is complete. W międzyczasie formant powraca do obiektu wywołującego bieżącej metody.In the meantime, control returns to the caller of the current method. W tym przykładzie bieżąca metoda jest GetURLContents, a obiekt wywołujący jest SumPageSizes.In this example, the current method is GetURLContents, and the caller is SumPageSizes. Po zakończeniu zadania zaznaczono obiekt WebResponse, który jest tworzony jako wartość oczekującego zadania i przypisany do zmiennej response.When the task is finished, the promised WebResponse object is produced as the value of the awaited task and assigned to the variable response.

    Poprzednią instrukcję można podzielić na dwie następujące instrukcje, aby wyjaśnić, co się dzieje.The previous statement can be separated into the following two statements to clarify what happens.

    //Task<WebResponse> responseTask = webReq.GetResponseAsync();
    //using (WebResponse response = await responseTask)
    

    Wywołanie webReq.GetResponseAsync zwraca Task(Of WebResponse) lub Task<WebResponse>.The call to webReq.GetResponseAsync returns a Task(Of WebResponse) or Task<WebResponse>. Następnie do zadania zostanie zastosowany operator await, aby pobrać wartość WebResponse.Then an await operator is applied to the task to retrieve the WebResponse value.

    Jeśli metoda async działa tak, aby nie zależała od ukończenia zadania, Metoda może kontynuować działanie między tymi dwiema instrukcjami po wywołaniu metody asynchronicznej i przed zastosowaniem operatora await.If your async method has work to do that doesn’t depend on the completion of the task, the method can continue with that work between these two statements, after the call to the async method and before the await operator is applied. Aby zapoznać się z przykładami, zobacz jak wykonywać wiele żądań sieci Web równolegle przy użyciu metodC#Async i Await () oraz jak rozłożyć Instruktaż asynchroniczny za pomocąC#metody Task. WhenAll ().For examples, see How to make multiple web requests in parallel by using async and await (C#) and How to extend the async walkthrough by using Task.WhenAll (C#).

  3. Ponieważ dodano operator await w poprzednim kroku, wystąpi błąd kompilatora.Because you added the await operator in the previous step, a compiler error occurs. Operatora można używać tylko w metodach, które są oznaczone modyfikatorem Async .The operator can be used only in methods that are marked with the async modifier. Zignoruj błąd podczas powtarzania kroków konwersji, aby zastąpić wywołanie do CopyTo z wywołaniem CopyToAsync.Ignore the error while you repeat the conversion steps to replace the call to CopyTo with a call to CopyToAsync.

    • Zmień nazwę metody, która jest wywoływana do CopyToAsync.Change the name of the method that’s called to CopyToAsync.

    • Metoda CopyTo lub CopyToAsync Kopiuje bajty do jej argumentu, contenti nie zwraca wartości znaczącej.The CopyTo or CopyToAsync method copies bytes to its argument, content, and doesn’t return a meaningful value. W wersji synchronicznej wywołanie CopyTo jest prostą instrukcją, która nie zwraca wartości.In the synchronous version, the call to CopyTo is a simple statement that doesn't return a value. Wersja asynchroniczna, CopyToAsync, zwraca Task.The asynchronous version, CopyToAsync, returns a Task. Zadanie działa jak "Task (void)" i umożliwia oczekiwanie metody.The task functions like "Task(void)" and enables the method to be awaited. Zastosuj Await lub await do wywołania CopyToAsync, jak pokazano w poniższym kodzie.Apply Await or await to the call to CopyToAsync, as the following code shows.

      await responseStream.CopyToAsync(content);
      

      Poprzednia instrukcja skraca następujące dwa wiersze kodu.The previous statement abbreviates the following two lines of code.

      // 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. Wszystkie te, które pozostały do wykonania w GetURLContents to dostosowanie sygnatury metody.All that remains to be done in GetURLContents is to adjust the method signature. Operatora await można używać tylko w metodach, które są oznaczone modyfikatorem Async .You can use the await operator only in methods that are marked with the async modifier. Dodaj modyfikator, aby oznaczyć metodę jako metodę asynchroniczną, jak pokazano w poniższym kodzie.Add the modifier to mark the method as an async method, as the following code shows.

    private async byte[] GetURLContents(string url)
    
  5. Zwracany typ metody asynchronicznej może być Task, Task<TResult>lub void w C#.The return type of an async method can only be Task, Task<TResult>, or void in C#. Zazwyczaj zwracany typ void jest używany tylko w obsłudze zdarzeń asynchronicznych, gdzie void jest wymagany.Typically, a return type of void is used only in an async event handler, where void is required. W innych przypadkach należy używać Task(T), jeśli metoda zakończona zawiera instrukcję Return , która zwraca wartość typu t, i używa Task, jeśli metoda zakończona nie zwraca wartości znaczącej.In other cases, you use Task(T) if the completed method has a return statement that returns a value of type T, and you use Task if the completed method doesn’t return a meaningful value. Można traktować Task typ zwracany jako znaczenie "zadanie (void)".You can think of the Task return type as meaning "Task(void)."

    Aby uzyskać więcej informacji, zobacz asynchroniczne typy zwracaneC#().For more information, see Async Return Types (C#).

    Metoda GetURLContents ma instrukcję return, a instrukcja zwraca tablicę bajtów.Method GetURLContents has a return statement, and the statement returns a byte array. W związku z tym zwracanym typem wersji asynchronicznej jest zadanie (T), gdzie T jest tablicą bajtów.Therefore, the return type of the async version is Task(T), where T is a byte array. Wprowadź następujące zmiany w podpisie metody:Make the following changes in the method signature:

    • Zmień zwracany typ na Task<byte[]>.Change the return type to Task<byte[]>.

    • Zgodnie z Konwencją metody asynchroniczne mają nazwy kończące się na "Async", więc Zmień nazwę metody GetURLContentsAsync.By convention, asynchronous methods have names that end in "Async," so rename the method GetURLContentsAsync.

    Poniższy kod przedstawia te zmiany.The following code shows these changes.

    private async Task<byte[]> GetURLContentsAsync(string url)
    

    Po wprowadzeniu tych zmian konwersja GetURLContents na metodę asynchroniczną zostanie zakończona.With those few changes, the conversion of GetURLContents to an asynchronous method is complete.

Konwertuj SumPageSizes na metodę asynchronicznąConvert SumPageSizes to an asynchronous method

  1. Powtórz kroki opisane w poprzedniej procedurze dla SumPageSizes.Repeat the steps from the previous procedure for SumPageSizes. Najpierw Zmień wywołanie GetURLContents na wywołanie asynchroniczne.First, change the call to GetURLContents to an asynchronous call.

    • Zmień nazwę metody, która jest wywoływana z GetURLContents na GetURLContentsAsync, jeśli jeszcze tego nie zrobiono.Change the name of the method that’s called from GetURLContents to GetURLContentsAsync, if you haven't already done so.

    • Zastosuj await do zadania, które GetURLContentsAsync zwraca, aby uzyskać wartość tablicy bajtowej.Apply await to the task that GetURLContentsAsync returns to obtain the byte array value.

    Poniższy kod przedstawia te zmiany.The following code shows these changes.

    byte[] urlContents = await GetURLContentsAsync(url);
    

    Poprzednie przypisanie skraca dwa następujące wiersze kodu.The previous assignment abbreviates the following two lines of code.

    // GetURLContentsAsync returns a Task<T>. At completion, the task
    // produces a byte array.
    //Task<byte[]> getContentsTask = GetURLContentsAsync(url);
    //byte[] urlContents = await getContentsTask;
    
  2. Wprowadź następujące zmiany w podpisie metody:Make the following changes in the method's signature:

    • Oznacz metodę za pomocą modyfikatora async.Mark the method with the async modifier.

    • Dodaj wartość "Async" do nazwy metody.Add "Async" to the method name.

    • Brak zmiennej zwracanej zadania, T, ten czas, ponieważ SumPageSizesAsync nie zwraca wartości dla T. (metoda nie ma return instrukcji.) Jednak metoda musi zwrócić Task, aby można było oczekiwać.There is no task return variable, T, this time because SumPageSizesAsync doesn’t return a value for T. (The method has no return statement.) However, the method must return a Task to be awaitable. W związku z tym Zmień zwracany typ metody z void na Task.Therefore, change the return type of the method from void to Task.

    Poniższy kod przedstawia te zmiany.The following code shows these changes.

    private async Task SumPageSizesAsync()
    

    Konwersja SumPageSizes na SumPageSizesAsync została zakończona.The conversion of SumPageSizes to SumPageSizesAsync is complete.

Konwertuj startButton_Click na metodę asynchronicznąConvert startButton_Click to an asynchronous method

  1. W programie obsługi zdarzeń Zmień nazwę wywołanej metody z SumPageSizes na SumPageSizesAsync, jeśli jeszcze tego nie zrobiono.In the event handler, change the name of the called method from SumPageSizes to SumPageSizesAsync, if you haven’t already done so.

  2. Ponieważ SumPageSizesAsync jest metodą asynchroniczną, Zmień kod w programie obsługi zdarzeń, aby oczekiwać na wynik.Because SumPageSizesAsync is an async method, change the code in the event handler to await the result.

    Wywołanie SumPageSizesAsync odzwierciedla wywołanie CopyToAsync w GetURLContentsAsync.The call to SumPageSizesAsync mirrors the call to CopyToAsync in GetURLContentsAsync. Wywołanie zwraca Task, a nie Task(T).The call returns a Task, not a Task(T).

    Jak w poprzednich procedurach, można skonwertować wywołanie przy użyciu jednej instrukcji lub dwóch instrukcji.As in previous procedures, you can convert the call by using one statement or two statements. Poniższy kod przedstawia te zmiany.The following code shows these changes.

    // One-step async call.
    await SumPageSizesAsync();
    
    // Two-step async call.
    //Task sumTask = SumPageSizesAsync();
    //await sumTask;
    
  3. Aby zapobiec przypadkowemu ponownemu wprowadzaniu operacji, Dodaj następującą instrukcję w górnej części startButton_Click, aby wyłączyć przycisk Uruchom .To prevent accidentally reentering the operation, add the following statement at the top of startButton_Click to disable the Start button.

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

    Przycisk można ponownie włączyć na końcu programu obsługi zdarzeń.You can reenable the button at the end of the event handler.

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

    Aby uzyskać więcej informacji na temat współużytkowania wątkowości, zobacz Obsługa współużytkowania wątkowości w aplikacjachC#asynchronicznych ().For more information about reentrancy, see Handling Reentrancy in Async Apps (C#).

  4. Na koniec Dodaj modyfikator async do deklaracji, aby program obsługi zdarzeń mógł oczekiwać SumPagSizesAsync.Finally, add the async modifier to the declaration so that the event handler can await SumPagSizesAsync.

    private async void startButton_Click(object sender, RoutedEventArgs e)
    

    Zazwyczaj nazwy programów obsługi zdarzeń nie są zmieniane.Typically, the names of event handlers aren’t changed. Zwracany typ nie jest zmieniany na Task, ponieważ programy obsługi zdarzeń muszą zwracać void.The return type isn’t changed to Task because event handlers must return void.

    Konwersja projektu z synchronicznego na przetwarzanie asynchroniczne zostało zakończone.The conversion of the project from synchronous to asynchronous processing is complete.

Przetestuj rozwiązanie asynchroniczneTest the asynchronous solution

  1. Wybierz klawisz F5 , aby uruchomić program, a następnie wybierz przycisk Start .Choose the F5 key to run the program, and then choose the Start button.

  2. Powinny pojawić się dane wyjściowe podobne do danych wyjściowych rozwiązania synchronicznego.Output that resembles the output of the synchronous solution should appear. Jednak Zwróć uwagę na następujące różnice.However, notice the following differences.

    • Wyniki nie są wykonywane w tym samym czasie po zakończeniu przetwarzania.The results don’t all occur at the same time, after the processing is complete. Na przykład oba programy zawierają wiersz w startButton_Click, który czyści pole tekstowe.For example, both programs contain a line in startButton_Click that clears the text box. Celem jest wyczyszczenie pola tekstowego między uruchomieniami w przypadku wybrania przycisku Rozpocznij po raz drugi, po wyświetleniu jednego zestawu wyników.The intent is to clear the text box between runs if you choose the Start button for a second time, after one set of results has appeared. W wersji synchronicznej, pole tekstowe jest czyszczone tuż przed wyświetleniem liczby po raz drugi, po ukończeniu pobierania, a wątek interfejsu użytkownika jest bezpłatny, aby wykonać inne czynności.In the synchronous version, the text box is cleared just before the counts appear for the second time, when the downloads are completed and the UI thread is free to do other work. W wersji asynchronicznej, pole tekstowe czyści natychmiast po wybraniu przycisku Rozpocznij .In the asynchronous version, the text box clears immediately after you choose the Start button.

    • Co najważniejsze, wątek interfejsu użytkownika nie jest blokowany podczas pobierania.Most importantly, the UI thread isn’t blocked during the downloads. Możesz przenosić lub zmieniać rozmiar okna, gdy zasoby sieci Web są pobierane, zliczane i wyświetlane.You can move or resize the window while the web resources are being downloaded, counted, and displayed. Jeśli jedna z witryn sieci Web działa wolno lub nie odpowiada, możesz anulować operację, wybierając przycisk Zamknij (x w czerwono w prawym górnym rogu).If one of the websites is slow or not responding, you can cancel the operation by choosing the Close button (the x in the red field in the upper-right corner).

Zastąp metodę GetURLContentsAsync metodą .NET FrameworkReplace method GetURLContentsAsync with a .NET Framework method

  1. .NET Framework 4,5 zawiera wiele metod asynchronicznych, których można użyć.The .NET Framework 4.5 provides many async methods that you can use. Jednym z nich jest GetByteArrayAsync(String)Metoda HttpClient, co jest potrzebne do tego przewodnika.One of them, the HttpClient method GetByteArrayAsync(String), does just what you need for this walkthrough. Można jej użyć zamiast metody GetURLContentsAsync utworzonej we wcześniejszej procedurze.You can use it instead of the GetURLContentsAsync method that you created in an earlier procedure.

    Pierwszym krokiem jest utworzenie obiektu HttpClient w SumPageSizesAsyncmetodzie.The first step is to create an HttpClient object in method SumPageSizesAsync. Dodaj następującą deklarację na początku metody.Add the following declaration at the start of the method.

    // Declare an HttpClient object and increase the buffer size. The
    // default buffer size is 65,536.
    HttpClient client =
        new HttpClient() { MaxResponseContentBufferSize = 1000000 };
    
  2. W SumPageSizesAsync, Zastąp wywołanie metody GetURLContentsAsync wywołaniem metody HttpClient.In SumPageSizesAsync, replace the call to your GetURLContentsAsync method with a call to the HttpClient method.

    byte[] urlContents = await client.GetByteArrayAsync(url);
    
  3. Usuń lub Skomentuj zapisaną metodę GetURLContentsAsync.Remove or comment out the GetURLContentsAsync method that you wrote.

  4. Wybierz klawisz F5 , aby uruchomić program, a następnie wybierz przycisk Start .Choose the F5 key to run the program, and then choose the Start button.

    Zachowanie tej wersji projektu powinno być zgodne z zachowaniem, że procedura "Aby przetestować rozwiązanie asynchroniczne" opisuje, ale nawet mniej wysiłku od użytkownika.The behavior of this version of the project should match the behavior that the "To test the asynchronous solution" procedure describes but with even less effort from you.

Przykładowy kodExample code

Poniższy kod zawiera pełny przykład konwersji z synchronicznego na asynchroniczne rozwiązanie przy użyciu metody asynchronicznego GetURLContentsAsync, która została zapisana.The following code contains the full example of the conversion from a synchronous to an asynchronous solution by using the asynchronous GetURLContentsAsync method that you wrote. Należy zauważyć, że silnie przypomina oryginalne, synchroniczne rozwiązanie.Notice that it strongly resembles the original, synchronous solution.

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 +=
                $"\r\n\r\nTotal bytes returned:  {total}\r\n";
        }

        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/library/hh290136.aspx",
                "https://msdn.microsoft.com/library/ee256749.aspx",
                "https://msdn.microsoft.com/library/hh290138.aspx",
                "https://msdn.microsoft.com/library/hh290140.aspx",
                "https://msdn.microsoft.com/library/dd470362.aspx",
                "https://msdn.microsoft.com/library/aa578028.aspx",
                "https://msdn.microsoft.com/library/ms404677.aspx",
                "https://msdn.microsoft.com/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 "https://".
            var displayURL = url.Replace("https://", "");
            resultsTextBox.Text += $"\n{displayURL,-58} {bytes,8}";
        }
    }
}

Poniższy kod zawiera pełny przykład rozwiązania, które używa metody HttpClient, GetByteArrayAsync.The following code contains the full example of the solution that uses the HttpClient method, GetByteArrayAsync.

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 +=
                $"\r\n\r\nTotal bytes returned:  {total}\r\n";
        }

        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/library/hh290136.aspx",
                "https://msdn.microsoft.com/library/ee256749.aspx",
                "https://msdn.microsoft.com/library/hh290138.aspx",
                "https://msdn.microsoft.com/library/hh290140.aspx",
                "https://msdn.microsoft.com/library/dd470362.aspx",
                "https://msdn.microsoft.com/library/aa578028.aspx",
                "https://msdn.microsoft.com/library/ms404677.aspx",
                "https://msdn.microsoft.com/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 "https://".
            var displayURL = url.Replace("https://", "");
            resultsTextBox.Text += $"\n{displayURL,-58} {bytes,8}";
        }
    }
}

Zobacz takżeSee also