Condividi tramite


Gestione della reentrancy nelle app asincrone (Visual Basic)

Quando si include codice asincrono nell'app, è consigliabile prendere in considerazione ed eventualmente impedire la reentrancy, che si riferisce alla reinserimento di un'operazione asincrona prima del completamento. Se non si identificano e gestiscono le possibilità di rientro, ciò può causare risultati imprevisti.

Annotazioni

Per eseguire l'esempio, è necessario che Nel computer sia installato Visual Studio 2012 o versione successiva e .NET Framework 4.5 o versione successiva.

Annotazioni

Transport Layer Security (TLS) versione 1.2 è ora la versione minima da usare nello sviluppo di app. Se l'app è destinata a una versione di .NET Framework precedente alla 4.7, vedere l'articolo seguente per le procedure consigliate di Transport Layer Security (TLS) con .NET Framework.

Riconoscimento della ri-entrabilità

Nell'esempio di questo argomento, gli utenti scelgono un pulsante Start per avviare un'app asincrona che scarica una serie di siti Web e calcola il numero totale di byte scaricati. Una versione sincrona dell'esempio risponde allo stesso modo indipendentemente dal numero di volte in cui un utente sceglie il pulsante perché, dopo la prima volta, il thread dell'interfaccia utente ignora tali eventi fino al termine dell'esecuzione dell'app. In un'app asincrona, tuttavia, il thread dell'interfaccia utente continua a rispondere e potrebbe essere necessario immettere nuovamente l'operazione asincrona prima del completamento.

L'esempio seguente mostra l'output previsto se l'utente sceglie il pulsante Start una sola volta. Viene visualizzato un elenco dei siti Web scaricati con le dimensioni, in byte, di ogni sito. Alla fine viene visualizzato il numero totale di byte.

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

Tuttavia, se l'utente sceglie più volte il pulsante, il gestore eventi viene richiamato ripetutamente e il processo di download viene immesso di nuovo ogni volta. Di conseguenza, diverse operazioni asincrone vengono eseguite contemporaneamente. L'output interlaccia i risultati e il numero totale di byte risulta confuso.

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

È possibile esaminare il codice che produce questo output scorrendo fino alla fine di questo argomento. È possibile sperimentare il codice scaricando la soluzione nel computer locale e quindi eseguendo il progetto WebsiteDownload o usando il codice alla fine di questo argomento per creare il proprio progetto Per altre informazioni e istruzioni, vedere Revisione ed esecuzione dell'app di esempio.

Gestione della ricalcatezza

Puoi gestire la reentrancy in diversi modi, a seconda di ciò che vuoi che l'app faccia. In questo argomento vengono illustrati gli esempi seguenti:

  • Disabilitare il pulsante Start

    Disabilitare il pulsante Start mentre l'operazione è in esecuzione in modo che l'utente non possa interromperlo.

  • Annullare e riavviare l'operazione

    Annullare qualsiasi operazione ancora in esecuzione quando l'utente sceglie di nuovo il pulsante Avvia e quindi lasciare che l'operazione richiesta più di recente continui.

  • Eseguire più operazioni e accodare i risultati

    Consentire l'esecuzione asincrona di tutte le operazioni richieste, ma coordinare la visualizzazione dell'output in modo che i risultati di ogni operazione vengano visualizzati insieme e in ordine.

Disabilitare il pulsante Start

È possibile bloccare il pulsante Start mentre un'operazione è in esecuzione disabilitando il pulsante nella parte superiore del StartButton_Click gestore eventi. È quindi possibile riabilitare il pulsante dall'interno di un Finally blocco al termine dell'operazione in modo che gli utenti possano eseguire di nuovo l'app.

Il codice seguente mostra queste modifiche, contrassegnate con asterischi. È possibile aggiungere le modifiche al codice alla fine di questo argomento oppure scaricare l'app completata da Async Samples: Reentrancy nelle app desktop .NET. Il nome del progetto è 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

In seguito alle modifiche, il pulsante non risponde durante AccessTheWebAsync il download dei siti Web, quindi il processo non può essere nuovamente immesso.

Annullare e riavviare l'operazione

Invece di disabilitare il pulsante Start , è possibile mantenere attivo il pulsante, ma, se l'utente sceglie di nuovo il pulsante, annullare l'operazione già in esecuzione e lasciare che l'operazione avviata più di recente continui.

Per ulteriori informazioni sull'annullamento, vedere Fine-Tuning La tua applicazione asincrona (Visual Basic).

Per configurare questo scenario, apportare le modifiche seguenti al codice di base fornito in Revisione ed esecuzione dell'app di esempio. È anche possibile scaricare l'app completa da Async Samples: Reentrancy nelle app .NET desktop. Il nome di questo progetto è CancelAndRestart.

  1. Dichiarare una CancellationTokenSource variabile, cts, che sia accessibile a tutti i metodi.

    Class MainWindow // Or Class MainPage
    
        ' *** Declare a System.Threading.CancellationTokenSource.
        Dim cts As CancellationTokenSource
    
  2. In StartButton_Click determinare se è già in corso un'operazione. Se il valore di cts è Nothing, non è già attiva alcuna operazione. Se il valore non è Nothing, l'operazione già in esecuzione viene annullata.

    ' *** If a download process is already underway, cancel it.
    If cts IsNot Nothing Then
        cts.Cancel()
    End If
    
  3. Impostare su cts un valore diverso che rappresenta il processo corrente.

    ' *** Now set cts to cancel the current process if the button is chosen again.
    Dim newCTS As CancellationTokenSource = New CancellationTokenSource()
    cts = newCTS
    
  4. Alla fine di StartButton_Click, il processo corrente è stato completato, quindi impostare di nuovo il valore di cts su Nothing.

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

Il codice seguente mostra tutte le modifiche in StartButton_Click. Le aggiunte sono contrassegnate con asterischi.

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

In AccessTheWebAsyncapportare le modifiche seguenti.

  • Aggiungere un parametro per accettare il token di annullamento da StartButton_Click.

  • Utilizzare il metodo GetAsync per scaricare i siti Web perché GetAsync accetta un parametro CancellationToken.

  • Prima di chiamare DisplayResults per visualizzare i risultati per ogni sito Web scaricato, verificare ct che l'operazione corrente non sia stata annullata.

Il codice seguente mostra queste modifiche, contrassegnate con asterischi.

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

Se si sceglie il pulsante Start più volte mentre l'app è in esecuzione, dovrebbe produrre risultati simili all'output seguente:

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

Per eliminare gli elenchi parziali, rimuovere il commento dalla prima riga di codice in StartButton_Click per cancellare la casella di testo ogni volta che l'utente riavvia l'operazione.

Eseguire più operazioni e mettere in coda l'output

Questo terzo esempio è il più complicato in quanto l'app avvia un'altra operazione asincrona ogni volta che l'utente sceglie il pulsante Start e tutte le operazioni vengono eseguite fino al completamento. Tutte le operazioni richieste scaricano siti Web dall'elenco in modo asincrono, ma l'output delle operazioni viene presentato in sequenza. Cioè, l'attività di download effettiva viene intercalata, come illustrato dall'output in Recognizing Reentrancy, ma l'elenco dei risultati per ogni gruppo viene presentato separatamente.

Le operazioni condividono un oggetto globale Task, pendingWork, che funge da gatekeeper per il processo di visualizzazione.

È possibile eseguire questo esempio incollando le modifiche nel codice in Compilazione dell'app oppure seguendo le istruzioni in Download dell'app per scaricare l'esempio e quindi eseguire il progetto QueueResults.

L'output seguente mostra il risultato se l'utente sceglie il pulsante Start una sola volta. L'etichetta lettera, A, indica che il risultato proviene dalla prima scelta del pulsante Start . I numeri mostrano l'ordine degli URL nell'elenco delle destinazioni di download.

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

Se l'utente sceglie il pulsante Start tre volte, l'app genera un output simile alle righe seguenti. Le righe di informazioni che iniziano con un segno di cancelletto (#) tracciano lo stato di avanzamento dell'applicazione.

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

I gruppi B e C iniziano prima del completamento del gruppo A, ma l'output per ogni gruppo viene visualizzato separatamente. Tutto l'output per il gruppo A viene visualizzato per primo, seguito da tutto l'output per il gruppo B e quindi da tutto l'output per il gruppo C. L'app visualizza sempre i gruppi in ordine e, per ogni gruppo, visualizza sempre le informazioni sui singoli siti Web nell'ordine in cui gli URL vengono visualizzati nell'elenco degli URL.

Tuttavia, non è possibile prevedere l'ordine in cui si verificano effettivamente i download. Dopo l'avvio di più gruppi, le attività di download generate sono tutte attive. Non puoi presupporre che A-1 verrà scaricato prima di B-1 e non puoi presupporre che A-1 verrà scaricato prima di A-2.

Definizioni globali

Il codice di esempio contiene le due dichiarazioni globali seguenti visibili da tutti i metodi.

Class MainWindow    ' Class MainPage in Windows Store app.

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

La Task variabile, pendingWork, supervisiona il processo di visualizzazione e impedisce a qualsiasi gruppo di interrompere l'operazione di visualizzazione di un altro gruppo. La variabile di caratteri, group, etichetta l'output di gruppi diversi per verificare che i risultati vengano visualizzati nell'ordine previsto.

Il Gestore Eventi Click

Il gestore eventi, StartButton_Click, incrementa la lettera di gruppo ogni volta che l'utente sceglie il pulsante Start . Il gestore chiama AccessTheWebAsync quindi per eseguire l'operazione di download.

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

Metodo AccessTheWebAsync

In questo esempio vengono suddivisi AccessTheWebAsync in due metodi. Il primo metodo, AccessTheWebAsync, avvia tutte le attività di download per un gruppo e configura pendingWork per controllare il processo di visualizzazione. Il metodo usa una query LINQ (Language Integrated Query) e ToArray per avviare tutte le attività di download contemporaneamente.

AccessTheWebAsync chiama quindi FinishOneGroupAsync per attendere il completamento di ogni download e visualizzarne la lunghezza.

FinishOneGroupAsync restituisce un'attività assegnata a pendingWork in AccessTheWebAsync. Tale valore impedisce l'interruzione di un'altra operazione prima del completamento dell'attività.

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

Metodo FinishOneGroupAsync

Questo metodo scorre attraverso le attività di download di un gruppo, attendendo ciascuna, mostrando la lunghezza del sito Web scaricato e aggiungendo la lunghezza al totale.

La prima istruzione in FinishOneGroupAsync usa pendingWork per assicurarsi che l'immissione del metodo non interferisca con un'operazione già presente nella procedura di visualizzazione o che è già in attesa. Se tale operazione è in corso, l'operazione di immissione deve attendere il suo turno.

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

È possibile eseguire questo esempio incollando le modifiche nel codice in Compilazione dell'app oppure seguendo le istruzioni in Download dell'app per scaricare l'esempio e quindi eseguire il progetto QueueResults.

Punti di interesse

Le righe di informazioni che iniziano con un segno di cancelletto (#) nell'output chiariscono il funzionamento di questo esempio.

L'output mostra i modelli seguenti.

  • È possibile avviare un gruppo durante la visualizzazione dell'output di un gruppo precedente, ma la visualizzazione dell'output del gruppo precedente non viene interrotta.

    #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
    
  • L'attività pendingWork è Nothing all'inizio di FinishOneGroupAsync solo per il gruppo A, che ha iniziato per primo. Il gruppo A non ha ancora completato un'espressione await quando raggiunge FinishOneGroupAsync. Di conseguenza, il controllo non è tornato a AccessTheWebAsynce la prima assegnazione a pendingWork non è stata eseguita.

  • Nell'output vengono sempre visualizzate le due righe seguenti. Il codice non viene mai interrotto tra l'avvio dell'operazione di un gruppo in StartButton_Click e l'assegnazione di un'attività per il gruppo a pendingWork.

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

    Dopo che un gruppo entra in StartButton_Click, l'operazione non completa un'espressione await finché l'operazione non entra in FinishOneGroupAsync. Pertanto, nessun'altra operazione può ottenere il controllo durante il segmento di codice.

Revisione ed esecuzione dell'app di esempio

Per comprendere meglio l'app di esempio, è possibile scaricarla, compilarla manualmente o esaminare il codice alla fine di questo argomento senza implementare l'app.

Annotazioni

Per eseguire l'esempio come app desktop Windows Presentation Foundation (WPF), è necessario che nel computer sia installato Visual Studio 2012 o versione successiva e .NET Framework 4.5 o versione successiva.

Download dell'app

  1. Scaricare il file compresso da Async Samples: Reentrancy in .NET Desktop Apps (Esempi asincroni: reentrancy in app desktop .NET).

  2. Decomprimere il file scaricato e quindi avviare Visual Studio.

  3. Sulla barra dei menu scegliere File, Apri, Progetto/Soluzione.

  4. Passare alla cartella che contiene il codice di esempio decompresso e quindi aprire il file della soluzione (.sln).

  5. In Esplora soluzioni aprire il menu di scelta rapida per il progetto da eseguire e quindi scegliere Imposta come StartUpProject.

  6. Scegliere i tasti CTRL+F5 per compilare ed eseguire il progetto.

Compilazione dell'app

La sezione seguente fornisce il codice per compilare l'esempio come app WPF.

Per compilare un'app WPF
  1. Avvia Visual Studio.

  2. Nella barra dei menu scegliere File, Nuovo, Progetto.

    Verrà visualizzata la finestra di dialogo Nuovo progetto .

  3. Nel riquadro Modelli installati espandere Visual Basic, quindi espandere Windows.

  4. Nell'elenco dei tipi di progetto scegliere Applicazione WPF.

  5. Assegnare al progetto WebsiteDownloadWPFil nome , scegliere .NET Framework versione 4.6 o successiva e quindi fare clic sul pulsante OK .

    Il nuovo progetto verrà visualizzato in Esplora soluzioni.

  6. Nell'Editor di codice di Visual Studio scegliere la scheda MainWindow.xaml .

    Se la scheda non è visibile, aprire il menu di scelta rapida per MainWindow.xaml in Esplora soluzioni e quindi scegliere Visualizza codice.

  7. Nella visualizzazione XAML di MainWindow.xaml sostituire il codice con il codice seguente.

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

    Una finestra semplice che contiene una casella di testo e un pulsante viene visualizzato nella visualizzazione Progettazione di MainWindow.xaml.

  8. In Esplora soluzioni fare clic con il pulsante destro del mouse su Riferimenti e scegliere Aggiungi riferimento.

    Aggiungere un riferimento per System.Net.Http, se non è già selezionato.

  9. In Esplora soluzioni aprire il menu di scelta rapida per MainWindow.xaml.vb e quindi scegliere Visualizza codice.

  10. In MainWindow.xaml.vb sostituire il codice con il codice seguente.

    ' 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. Scegliere i tasti CTRL+F5 per eseguire il programma e quindi scegliere il pulsante Start più volte.

  12. Apporta le modifiche da Disabilita il pulsante Start, a Annulla e riavvia l'operazione, oppure a Esegui più operazioni e accoda l'output per gestire la rientranza.

Vedere anche