共用方式為


處理異步應用程式中的重入性(Visual Basic)

當您在應用程式中包含異步程式代碼時,您應該考慮並可能防止重入性,這指的是在異步操作完成之前重新進入該操作。 如果您未識別並處理重新進入的可能性,可能會導致非預期的結果。

備註

若要執行此範例,您必須在計算機上安裝Visual Studio 2012或更新版本,以及已安裝 .NET Framework 4.5 或更新版本。

備註

傳輸層安全性 (TLS) 1.2 版現在是應用程式開發中使用的最低版本。 如果您的應用程式以 4.7 之前的 .NET Framework 版本為目標,請參閱下列文章,瞭解 .NET Framework 的傳輸層安全性(TLS) 最佳做法

識別重新進入

在本主題的範例中,用戶選擇 [ 開始 ] 按鈕來起始異步應用程式,以下載一系列網站,並計算所下載的位元組總數。 在此範例的同步版本中,無論使用者點擊按鈕多少次,在第一次點擊之後,因為應用程式正在執行,所以 UI 執行緒會忽略這些事件。 不過,在異步應用程式中,UI 線程會繼續回應,而且您可能會在完成之前重新進入異步操作。

如果使用者只選擇 [ 開始 ] 按鈕一次,下列範例會顯示預期的輸出。 下載的網站清單會顯示每個網站的大小,以位元組為單位。 位元組總數會出現在結尾。

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

不過,如果使用者選擇按鈕一次以上,則會重複叫用事件處理程式,而且每次都會重新輸入下載程式。 因此,會同時執行數個異步作業,結果交錯顯示,而且位元組的總數令人感到混淆。

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

您可以捲動至本主題結尾,以檢閱產生此輸出的程序代碼。 您可以將方案下載至本機計算機,然後執行 WebsiteDownload 專案,或使用本主題結尾的程式代碼來建立您自己的專案,以實驗程式代碼。如需詳細資訊和指示,請參閱 檢閱和執行範例應用程式

處理重新進入

您可以根據應用程式要執行的動作,以各種方式處理重新進入。 本主題提供下列範例:

停用 [開始] 按鈕

您可以在作業執行時封鎖 [開始 ] 按鈕,方法是停用事件處理程式頂端的 StartButton_Click 按鈕。 接著,您可以在作業完成時,從 區塊內 Finally 重新啟用按鈕,讓使用者可以再次執行應用程式。

下列程式代碼顯示這些變更,這些變更會以星號標示。 您可以在本主題結尾將變更新增至程式碼,也可以從 異步樣本:.NET 桌面應用程式中的重新進入性下載已完成的應用程式。 專案名稱為 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

由於變更,按鈕在下載網站時 AccessTheWebAsync 不會回應,因此無法重新進行該程序。

取消並重新啟動作業

您可以不要停用 [ 開始 ] 按鈕,而是可以讓按鈕保持作用中,但是,如果使用者再次選擇該按鈕,請取消已經執行的作業,並讓最近啟動的作業繼續進行。

如需有關取消作業的詳細資訊,請參閱 Fine-Tuning 您的異步應用程式(Visual Basic)

若要設定此案例,請對 檢閱和執行範例應用程式中提供的基本程式代碼進行下列變更。 您也可以從 異步範例:.NET 桌面應用程式中的重新進入中下載已完成的應用程式。 此專案的名稱為 CancelAndRestart。

  1. CancellationTokenSource宣告變數 ,cts這是所有方法的範圍。

    Class MainWindow // Or Class MainPage
    
        ' *** Declare a System.Threading.CancellationTokenSource.
        Dim cts As CancellationTokenSource
    
  2. StartButton_Click中,判斷作業是否已經進行中。 如果 cts 的值是 Nothing,則目前沒有任何作業在進行中。 如果值不是 Nothing,則會取消已經執行的作業。

    ' *** If a download process is already underway, cancel it.
    If cts IsNot Nothing Then
        cts.Cancel()
    End If
    
  3. 設定 cts 為代表目前進程的不同值。

    ' *** Now set cts to cancel the current process if the button is chosen again.
    Dim newCTS As CancellationTokenSource = New CancellationTokenSource()
    cts = newCTS
    
  4. StartButton_Click 結束時,目前的程式已完成,因此請將 cts 的值設定回 Nothing

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

下列程式代碼顯示 StartButton_Click 中的所有變更。 新增專案會以星號標示。

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

AccessTheWebAsync 中進行下列變更。

  • 新增參數以接受 來自 StartButton_Click的取消令牌。

  • 使用GetAsync方法來下載網站,因為GetAsync接受CancellationToken參數。

  • 呼叫 DisplayResults 以顯示每個已下載網站的結果之前,請先檢查 ct 以確認目前作業尚未取消。

下列程式代碼顯示這些變更,這些變更會以星號標示。

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

如果您在執行此應用程式時選擇 [ 開始 ] 按鈕數次,它應該會產生類似下列輸出的結果:

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

若要排除部分清單,請在StartButton_Click中取消註解第一行程式碼,以便在每次使用者重新啟動操作時清除文字框。

執行多個作業並將輸出放入佇列

此第三個範例最為複雜,因為每次用戶選擇 開始 按鈕時,該應用程式就會啟動另一個異步操作,並且所有操作均會完整執行。 所有要求的作業都會以異步方式從清單下載網站,但作業的輸出會循序呈現。 也就是說,每個群組的結果清單會分開呈現,並且實際的下載活動是交錯進行的,這一點可以在 認知複入性 中的輸出中看到。

作業會共用全域 TaskpendingWork,做為顯示程式的閘道守衛。

您可以將變更貼到 建置應用程式中的程序代碼,也可以依照 下載應用程式 中的指示下載範例,然後執行 QueueResults 專案來執行此範例。

如果使用者只選擇 [ 開始 ] 按鈕一次,下列輸出會顯示結果。 字母標籤 A 表示結果來自第一次選擇 [ 開始 ] 按鈕。 數字會顯示下載目標清單中的 URL 順序。

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

如果使用者選擇 [ 開始 ] 按鈕三次,應用程式會產生類似下列幾行的輸出。 以磅號 (#) 開頭的信息行會追蹤應用程式的進度。

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

群組 B 和 C 會在群組 A 完成之前啟動,但每個群組的輸出會個別顯示。 群組 A 的所有輸出都會先出現,後面接著群組 B 的所有輸出,然後顯示群組 C 的所有輸出。應用程式一律會依序顯示群組,而且針對每個群組,一律會依URL清單中顯示URL的順序,顯示個別網站的相關信息。

不過,您無法預測下載實際發生的順序。 啟動多個群組之後,產生的下載工作全都處於作用中狀態。 您無法假設 A-1 會在 B-1 之前下載,而且您無法假設 A-1 會在 A-2 之前下載。

全域定義

範例程式代碼包含下列兩個全域宣告,這些宣告可從所有方法中看到。

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)

變數TaskpendingWork會監督顯示程式,並防止任何群組中斷另一個群組的顯示作業。 字元變數 group會標記不同群組的輸出,以確認結果會以預期的順序顯示。

Click 事件處理程式

事件處理程式 StartButton_Click會在使用者每次選擇 [ 開始 ] 按鈕時遞增組號。 然後處理程式會呼叫 AccessTheWebAsync 來執行下載作業。

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

AccessTheWebAsync 方法

此範例分成 AccessTheWebAsync 兩種方法。 第一種方法 AccessTheWebAsync會啟動群組的所有下載工作,並設定 pendingWork 以控制顯示程式。 方法會使用 Language Integrated Query(LINQ 查詢),並 ToArray 同時啟動所有的下載任務。

AccessTheWebAsync 然後呼叫 FinishOneGroupAsync 以等候每個下載完成,並顯示其長度。

FinishOneGroupAsync 會傳回指派給 pendingWork 的在 AccessTheWebAsync 的工作。 該值會在工作完成之前防止另一個作業中斷。

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

    Dim client = New HttpClient()

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

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

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

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

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

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

FinishOneGroupAsync 方法

這個方法會循環瀏覽群組中的下載任務,等候每個任務,顯示已下載網站的內容長度,並將內容長度新增至總計。

中的 FinishOneGroupAsync 第一個語句會使用 pendingWork ,以確保輸入 方法不會干擾已經在顯示程式中或已經在等候中的作業。 如果這類作業正在進行中,輸入作業必須等候其回合。

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

您可以將變更貼到 建置應用程式中的程式碼,或依照 下載應用程式 以下載範例中的指示執行此範例,然後執行 QueueResults 專案。

景點

輸出中以磅號 (#) 開頭的信息行會釐清此範例的運作方式。

輸出會顯示下列模式。

  • 在上一個群組顯示其輸出時,可以啟動群組,但上一個群組輸出的顯示不會中斷。

    #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
    
  • 第一個啟動的群組 A 的pendingWork工作只在Nothing的開始由FinishOneGroupAsync執行。 群組 A 尚未在到達 FinishOneGroupAsync時完成 await 運算式。 因此,控件尚未傳回至 AccessTheWebAsync,且對 pendingWork 的第一個指派尚未發生。

  • 下列兩行一律會出現在輸出中。 在 中 StartButton_Click 啟動群組的作業,以及將群組的工作指派給 pendingWork之間,程式代碼永遠不會中斷。

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

    在群組輸入 StartButton_Click之後,作業不會完成 await 運算式,直到作業進入 FinishOneGroupAsync為止。 因此,在該程式代碼區段期間,沒有其他作業可以取得控制權。

檢閱和執行範例應用程式

若要進一步瞭解範例應用程式,您可以自行下載、自行建置,或在本主題結尾檢閱程序代碼,而不實作應用程式。

備註

若要以 Windows Presentation Foundation(WPF) 傳統型應用程式的形式執行此範例,您必須在電腦上安裝 Visual Studio 2012 或更新版本,以及已安裝 .NET Framework 4.5 或更新版本。

下載應用程式

  1. Async Samples: 在 .NET Desktop Apps 中的重入 下載壓縮檔。

  2. 解壓縮您下載的檔案,然後啟動 Visual Studio。

  3. 在功能表欄上,選擇 [ 檔案]、[ 開啟]、[ 專案/方案]。

  4. 流覽至保存解壓縮範例程式代碼的資料夾,然後開啟方案 (.sln) 檔案。

  5. [方案總管] 中,開啟您要執行之專案的快捷方式功能表,然後選擇 [ 設定為 StartUpProject]。

  6. 選擇 CTRL+F5 鍵來建置並執行專案。

建置應用程式

下一節提供程式碼,以 WPF 應用程式的形式建置範例。

建置 WPF 應用程式
  1. 啟動 Visual Studio。

  2. 在功能表欄上,選擇 [ 檔案]、[ 新增]、[ 專案]。

    [ 新增專案 ] 對話框隨即開啟。

  3. 在 [ 已安裝的範本 ] 窗格中,展開 [Visual Basic],然後展開 [Windows]。

  4. 在專案類型清單中,選擇 [WPF 應用程式]。

  5. 將專案 WebsiteDownloadWPF命名為 ,選擇 4.6 或更高版本的 .NET Framework 版本,然後按兩下 [ 確定] 按鈕。

    新的專案會出現在 [方案總管] 中。

  6. 在 Visual Studio Code 編輯器中,選擇 MainWindow.xaml 索引標籤

    如果看不到索引標籤,請在 [方案總管] 中開啟 MainWindow.xaml 的快捷方式選單,然後選擇 [檢視程式碼]。

  7. 在MainWindow.xaml的 XAML 檢視中,將程式代碼取代為下列程序代碼。

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

    包含文字框和按鈕的簡單視窗會出現在MainWindow.xaml 的設計 檢視中。

  8. [方案總管] 中,以滑鼠右鍵按兩下 [ 參考 ],然後選取 [ 新增參考]。

    如果尚未選取System.Net.Http,請新增此參考。

  9. [方案總管] 中,開啟MainWindow.xaml.vb的快捷方式功能表,然後選擇 [ 檢視程序代碼]。

  10. 在 MainWindow.xaml.vb 中,將程式代碼取代為下列程序代碼。

    ' 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. 選擇 CTRL+F5 鍵以執行程式,然後選擇 [ 開始 ] 按鈕數次。

  12. 停用開始按鈕取消並重新啟動操作,或者 執行多個操作並將輸出排入佇列,以處理重入性。

另請參閱