Obsługa ponownego uwierzytelniania w aplikacjach asynchronicznych (Visual Basic)

W przypadku uwzględnienia kodu asynchronicznego w aplikacji należy rozważyć ponowne wprowadzenie operacji asynchronicznej, co oznacza ponowne wprowadzenie operacji asynchronicznej przed jej zakończeniem. Jeśli nie zidentyfikujesz i nie obsłużysz możliwości ponownego wywołania, może to spowodować nieoczekiwane wyniki.

Uwaga

Aby uruchomić przykład, na komputerze musi być zainstalowany program Visual Studio 2012 lub nowszy oraz program .NET Framework 4.5 lub nowszy.

Uwaga

Protokół Transport Layer Security (TLS) w wersji 1.2 jest teraz minimalną wersją do użycia w programowania aplikacji. Jeśli aplikacja jest przeznaczona dla platformy .NET Framework w wersji starszej niż 4.7, zapoznaj się z następującym artykułem , aby zapoznać się z najlepszymi rozwiązaniami dotyczącymi protokołu Transport Layer Security (TLS) w programie .NET Framework.

Rozpoznawanie ponownej reentrancy

W przykładzie w tym temacie użytkownicy wybierają przycisk Uruchom , aby zainicjować aplikację asynchroniczną, która pobiera serię witryn internetowych i oblicza łączną liczbę pobranych bajtów. Synchroniczna wersja przykładu będzie odpowiadać w taki sam sposób niezależnie od tego, ile razy użytkownik wybierze przycisk, ponieważ po pierwszym uruchomieniu wątek interfejsu użytkownika ignoruje te zdarzenia do momentu zakończenia działania aplikacji. Jednak w aplikacji asynchronicznej wątek interfejsu użytkownika nadal odpowiada i możesz ponownie wnieść operację asynchroniczną przed jej zakończeniem.

W poniższym przykładzie pokazano oczekiwane dane wyjściowe, jeśli użytkownik wybierze przycisk Uruchom tylko raz. Zostanie wyświetlona lista pobranych witryn internetowych o rozmiarze (w bajtach) każdej witryny. Łączna liczba bajtów jest wyświetlana na końcu.

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

Jeśli jednak użytkownik wybierze przycisk więcej niż raz, program obsługi zdarzeń jest wywoływany wielokrotnie, a proces pobierania jest ponownie pobierany za każdym razem. W związku z tym kilka operacji asynchronicznych jest uruchomionych w tym samym czasie, dane wyjściowe przeplatają wyniki, a łączna liczba bajtów jest myląca.

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

Możesz przejrzeć kod, który generuje te dane wyjściowe, przewijając na końcu tego tematu. Możesz eksperymentować z kodem, pobierając rozwiązanie na komputer lokalny, a następnie uruchamiając projekt WebsiteDownload lub używając kodu na końcu tego tematu, aby utworzyć własny projekt Aby uzyskać więcej informacji i instrukcji, zobacz Przeglądanie i uruchamianie przykładowej aplikacji.

Obsługa ponownej reentrancy

Reentrancy można obsługiwać na różne sposoby, w zależności od tego, co aplikacja ma robić. W tym temacie przedstawiono następujące przykłady:

  • Wyłącz przycisk Start

    Wyłącz przycisk Uruchom, gdy operacja jest uruchomiona, aby użytkownik nie mógł go przerwać.

  • Anuluj i uruchom ponownie operację

    Anuluj dowolną operację, która jest nadal uruchomiona, gdy użytkownik ponownie wybierze przycisk Uruchom , a następnie pozwól na kontynuowanie ostatnio żądanej operacji.

  • Uruchamianie wielu operacji i kolejki danych wyjściowych

    Zezwalaj na wykonywanie wszystkich żądanych operacji asynchronicznie, ale koordynowanie wyświetlania danych wyjściowych w taki sposób, aby wyniki z każdej operacji pojawiały się razem i w kolejności.

Wyłącz przycisk Start

Przycisk Uruchom można zablokować, gdy operacja jest uruchomiona, wyłączając przycisk w górnej części programu obsługi zdarzeńStartButton_Click. Następnie można ponownie przywrócić przycisk z bloku Finally po zakończeniu operacji, aby użytkownicy mogli ponownie uruchomić aplikację.

Poniższy kod przedstawia te zmiany, które są oznaczone gwiazdkami. Możesz dodać zmiany do kodu na końcu tego tematu lub pobrać ukończoną aplikację z sekcji Async Samples: Reentrancy in .NET Desktop Apps (Asynchroniczne przykłady: ponowne wprowadzenie w aplikacjach klasycznych platformy .NET). Nazwa projektu to 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

W wyniku zmian przycisk nie odpowiada podczas AccessTheWebAsync pobierania witryn internetowych, więc nie można ponownie entered procesu.

Anuluj i uruchom ponownie operację

Zamiast wyłączać przycisk Start , możesz zachować aktywny przycisk, ale jeśli użytkownik wybierze ten przycisk ponownie, anuluj operację, która jest już uruchomiona i niech ostatnio uruchomiona operacja będzie kontynuowana.

Aby uzyskać więcej informacji na temat anulowania, zobacz Dostosowywanie aplikacji asynchronicznych (Visual Basic).

Aby skonfigurować ten scenariusz, wprowadź następujące zmiany w podstawowym kodzie podanym w artykule Przeglądanie i uruchamianie przykładowej aplikacji. Możesz również pobrać ukończoną aplikację z sekcji Async Samples: Reentrancy in .NET Desktop Apps (Przykłady asynchroniczne: ponowne wprowadzenie w aplikacjach klasycznych platformy .NET). Nazwa tego projektu to CancelAndRestart.

  1. Zadeklaruj zmienną CancellationTokenSource , ctsktóra jest w zakresie dla wszystkich metod.

    Class MainWindow // Or Class MainPage
    
        ' *** Declare a System.Threading.CancellationTokenSource.
        Dim cts As CancellationTokenSource
    
  2. W StartButton_Clickpliku określ, czy operacja jest już w toku. Jeśli wartość to Nothing, żadna cts operacja nie jest już aktywna. Jeśli wartość nie Nothingjest , operacja, która jest już uruchomiona, została anulowana.

    ' *** If a download process is already underway, cancel it.
    If cts IsNot Nothing Then
        cts.Cancel()
    End If
    
  3. Ustaw cts na inną wartość reprezentującą bieżący proces.

    ' *** Now set cts to cancel the current process if the button is chosen again.
    Dim newCTS As CancellationTokenSource = New CancellationTokenSource()
    cts = newCTS
    
  4. Na końcu bieżącego StartButton_Clickprocesu jest ukończony, więc ustaw wartość cts z powrotem na Nothing.

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

Poniższy kod przedstawia wszystkie zmiany w pliku StartButton_Click. Dodatki są oznaczone gwiazdkami.

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

W AccessTheWebAsyncpliku wprowadź następujące zmiany.

  • Dodaj parametr, aby zaakceptować token anulowania z .StartButton_Click

  • GetAsync Użyj metody , aby pobrać witryny internetowe, ponieważ GetAsync akceptuje CancellationToken argument.

  • Przed wywołaniem polecenia DisplayResults w celu wyświetlenia wyników dla każdej pobranej witryny internetowej sprawdź ct , czy bieżąca operacja nie została anulowana.

Poniższy kod przedstawia te zmiany, które są oznaczone gwiazdkami.

' *** 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

Jeśli wybierzesz przycisk Uruchom kilka razy, gdy ta aplikacja jest uruchomiona, powinny zostać wyświetlone wyniki podobne do następujących danych wyjściowych:

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

Aby wyeliminować częściowe listy, usuń komentarz z pierwszego wiersza kodu, StartButton_Click aby wyczyścić pole tekstowe za każdym razem, gdy użytkownik ponownie uruchomi operację.

Uruchamianie wielu operacji i kolejki danych wyjściowych

Ten trzeci przykład jest najbardziej skomplikowany w tym, że aplikacja uruchamia kolejną operację asynchroniczną za każdym razem, gdy użytkownik wybierze przycisk Uruchom , a wszystkie operacje są uruchamiane do ukończenia. Wszystkie żądane operacje pobierają witryny internetowe z listy asynchronicznie, ale dane wyjściowe z operacji są prezentowane sekwencyjnie. Oznacza to, że rzeczywiste działanie pobierania jest przeplatane, jak wynika z danych wyjściowych w sekcji Rozpoznawanie reentrancy , ale lista wyników dla każdej grupy jest prezentowana oddzielnie.

Operacje współużytkują globalny Taskelement , pendingWorkktóry służy jako strażnik procesu wyświetlania.

Możesz uruchomić ten przykład, wklejając zmiany w kodzie w sekcji Kompilowanie aplikacji lub postępując zgodnie z instrukcjami w temacie Pobieranie aplikacji , aby pobrać przykład, a następnie uruchomić projekt QueueResults.

Poniższe dane wyjściowe pokazują wynik, jeśli użytkownik wybierze przycisk Uruchom tylko raz. Etykieta litery A wskazuje, że wynik pochodzi od pierwszego wybrania przycisku Start . Liczby pokazują kolejność adresów URL na liście elementów docelowych pobierania.

#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.

Jeśli użytkownik wybierze przycisk Uruchom trzy razy, aplikacja generuje dane wyjściowe podobne do następujących wierszy. Wiersze informacji rozpoczynające się od znaku funta (#) śledzą postęp aplikacji.

#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.

Grupy B i C rozpoczynają się przed zakończeniem grupy A, ale dane wyjściowe dla każdej grupy są wyświetlane oddzielnie. Wszystkie dane wyjściowe grupy A są wyświetlane jako pierwsze, a następnie wszystkie dane wyjściowe grupy B, a następnie wszystkie dane wyjściowe grupy C. Aplikacja zawsze wyświetla grupy w kolejności, a dla każdej grupy zawsze wyświetla informacje o poszczególnych witrynach internetowych w kolejności, w których adresy URL są wyświetlane na liście adresów URL.

Nie można jednak przewidzieć kolejności rzeczywistej pobierania. Po uruchomieniu wielu grup wszystkie wygenerowane przez nie zadania pobierania są aktywne. Nie można założyć, że A-1 zostanie pobrany przed B-1 i nie można założyć, że A-1 zostanie pobrany przed A-2.

Definicje globalne

Przykładowy kod zawiera następujące dwie deklaracje globalne, które są widoczne we wszystkich metodach.

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)

Zmienna Task , pendingWorknadzoruje proces wyświetlania i uniemożliwia każdej grupie przerwanie operacji wyświetlania innej grupy. Zmienna znaku , groupoznacza dane wyjściowe z różnych grup, aby sprawdzić, czy wyniki są wyświetlane w oczekiwanej kolejności.

Procedura obsługi zdarzeń kliknięcia

Program obsługi zdarzeń zwiększa StartButton_Clickliterę grupy za każdym razem, gdy użytkownik wybierze przycisk Uruchom . Następnie program obsługi wywołuje polecenie AccessTheWebAsync , aby uruchomić operację pobierania.

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

Metoda AccessTheWebAsync

Ten przykład dzieli się AccessTheWebAsync na dwie metody. Pierwsza metoda , AccessTheWebAsyncuruchamia wszystkie zadania pobierania dla grupy i konfiguruje w pendingWork celu kontrolowania procesu wyświetlania. Metoda używa zapytania zintegrowanego języka (zapytanie LINQ) i ToArray uruchamia wszystkie zadania pobierania w tym samym czasie.

AccessTheWebAsync następnie wywołuje polecenie FinishOneGroupAsync , aby oczekiwać na ukończenie każdego pobierania i wyświetlić jego długość.

FinishOneGroupAsync Zwraca zadanie przydzielone do pendingWork metody w programie AccessTheWebAsync. Ta wartość uniemożliwia przerwanie działania przez inną operację przed ukończeniem zadania.

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

Metoda FinishOneGroupAsync

Ta metoda przechodzi przez zadania pobierania w grupie, oczekując na każdy z nich, wyświetlając długość pobranej witryny internetowej i dodając długość do sumy.

Pierwsza instrukcja w FinishOneGroupAsync użyciu pendingWork służy do upewnienia się, że wprowadzenie metody nie zakłóca operacji, która jest już w procesie wyświetlania lub która już czeka. Jeśli taka operacja jest w toku, operacja wejściowa musi czekać na jego obrót.

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

Możesz uruchomić ten przykład, wklejając zmiany w kodzie w sekcji Kompilowanie aplikacji lub postępując zgodnie z instrukcjami w temacie Pobieranie aplikacji , aby pobrać przykład, a następnie uruchomić projekt QueueResults.

Zainteresowania

Wiersze informacji rozpoczynające się od znaku funta (#) w danych wyjściowych wyjaśniają, jak działa ten przykład.

Dane wyjściowe przedstawiają następujące wzorce.

  • Grupę można uruchomić, gdy poprzednia grupa wyświetla swoje dane wyjściowe, ale wyświetlanie danych wyjściowych poprzedniej grupy nie jest przerywane.

    #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
    
  • Zadanie pendingWork jest Nothing na początku FinishOneGroupAsync tylko dla grupy A, która została uruchomiona jako pierwsza. Grupa A nie ukończyła jeszcze wyrażenia await, gdy osiągnie FinishOneGroupAsyncwartość . W związku z tym kontrolka nie została zwrócona do AccessTheWebAsync, a pierwsze przypisanie pendingWork do elementu nie miało miejsca.

  • Następujące dwa wiersze są zawsze wyświetlane razem w danych wyjściowych. Kod nigdy nie jest przerywany między uruchomieniem operacji grupy w StartButton_Click programie i przypisaniem zadania dla grupy do elementu pendingWork.

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

    Po wprowadzeniu StartButton_Clickgrupy operacja nie ukończy wyrażenia await, dopóki operacja nie zostanie wprowadzona FinishOneGroupAsync. W związku z tym żadna inna operacja nie może przejąć kontroli nad tym segmentem kodu.

Przeglądanie i uruchamianie przykładowej aplikacji

Aby lepiej zrozumieć przykładowy aplikację, możesz ją pobrać, skompilować ją samodzielnie lub przejrzeć kod na końcu tego tematu bez implementowania aplikacji.

Uwaga

Aby uruchomić przykład jako aplikację klasyczną programu Windows Presentation Foundation (WPF), na komputerze musi być zainstalowany program Visual Studio 2012 lub nowszy oraz program .NET Framework 4.5 lub nowszy.

Pobieranie aplikacji

  1. Pobierz skompresowany plik z przykładów asynchronicznych: ponowne wprowadzenie w aplikacjach klasycznych platformy .NET.

  2. Zdekompresuj pobrany plik, a następnie uruchom program Visual Studio.

  3. Na pasku menu wybierz pozycję Plik, Otwórz, Projekt/Rozwiązanie.

  4. Przejdź do folderu zawierającego zdekompresowany przykładowy kod, a następnie otwórz plik rozwiązania (.sln).

  5. W Eksplorator rozwiązań otwórz menu skrótów dla projektu, który chcesz uruchomić, a następnie wybierz pozycję Ustaw jako StartUpProject.

  6. Wybierz klawisze CTRL+F5, aby skompilować i uruchomić projekt.

Kompilowanie aplikacji

Poniższa sekcja zawiera kod umożliwiający skompilowanie przykładu jako aplikacji WPF.

Aby utworzyć aplikację WPF
  1. Uruchom program Visual Studio.

  2. Na pasku menu wybierz pozycję Plik, Nowy, Projekt.

    Zostanie otwarte okno dialogowe Nowy projekt .

  3. W okienku Zainstalowane szablony rozwiń węzeł Visual Basic, a następnie rozwiń węzeł Windows.

  4. Na liście typów projektów wybierz pozycję Aplikacja WPF.

  5. Nadaj projektowi WebsiteDownloadWPFnazwę , wybierz wersję programu .NET Framework w wersji 4.6 lub nowszej , a następnie kliknij przycisk OK .

    Nowy projekt zostanie wyświetlony w Eksplorator rozwiązań.

  6. W edytorze programu Visual Studio Code wybierz kartę MainWindow.xaml .

    Jeśli karta nie jest widoczna, otwórz menu skrótów dla pliku MainWindow.xaml w Eksplorator rozwiązań, a następnie wybierz pozycję Wyświetl kod.

  7. W widoku XAML pliku MainWindow.xaml zastąp kod następującym kodem.

    <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>
    

    Proste okno zawierające pole tekstowe i przycisk pojawi się w widoku Projekt mainWindow.xaml.

  8. W Eksplorator rozwiązań kliknij prawym przyciskiem myszy pozycję Odwołania i wybierz pozycję Dodaj odwołanie.

    Dodaj odwołanie dla elementu System.Net.Http, jeśli nie zostało jeszcze wybrane.

  9. W Eksplorator rozwiązań otwórz menu skrótów dla MainWindow.xaml.vb, a następnie wybierz pozycję Wyświetl kod.

  10. W MainWindow.xaml.vb zastąp kod następującym kodem.

    ' 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. Wybierz klawisze CTRL+F5, aby uruchomić program, a następnie wybierz przycisk Uruchom kilka razy.

  12. Wprowadź zmiany w obszarze Wyłącz przycisk Uruchamiania, Anuluj i Uruchom ponownie operację lub Uruchom wiele operacji i utwórz kolejkę danych wyjściowych , aby obsłużyć ponowne uruchomienie.

Zobacz też