Asynchronous Programming

30.1 Async/Await Basics

Imports System.Net.Http

Public Async Function DownloadPageAsync(url As String) As Task(Of Integer)
    Using client As New HttpClient()
        Dim content As String = Await client.GetStringAsync(url)
        Return content.Length
    End Using
End Function

Public Async Function MainAsync() As Task
    Dim length = Await DownloadPageAsync("https://learn.microsoft.com")
    Console.WriteLine($"Downloaded {length} chars")
End Function

Sub Main()
    MainAsync().GetAwaiter().GetResult()      ' VB doesn't support Async Sub Main, so block at the entry point
End Sub

30.2 Return Types

Async operation with no result Async operation returning T Only for event handlers (exceptions can't be awaited) ValueTask(Of T) High-performance scenarios (consume)

30.3 Running Tasks Concurrently

Async Function ProcessAllAsync() As Task
    Dim urls = {"https://example.com", "https://dotnet.microsoft.com", "https://github.com"}
    Dim tasks = urls.Select(Function(u) DownloadPageAsync(u)).ToList()
    Dim results As Integer() = Await Task.WhenAll(tasks)          ' wait for all
    Console.WriteLine($"Total: {results.Sum()}")

    Dim first = Await Task.WhenAny(tasks)                           ' first completed
    Await Task.Delay(500)                                           ' non-blocking delay
    Dim cpuResult = Await Task.Run(Function() HeavyComputation())   ' offload CPU work to the thread pool
End Function

30.4 Cancellation and Progress

Async Function LongOperationAsync(progress As IProgress(Of Integer), token As Threading.CancellationToken) As Task
    For i = 1 To 100
        token.ThrowIfCancellationRequested()
        Await Task.Delay(50, token)
        progress?.Report(i)
    Next
End Function

Dim cts As New Threading.CancellationTokenSource(TimeSpan.FromSeconds(10))
Dim prog As New Progress(Of Integer)(Sub(p) Console.Write($"{p}% "))
Try
    Await LongOperationAsync(prog, cts.Token)
Catch ex As OperationCanceledException
    Console.WriteLine("Cancelled.")
End Try
' cts.Cancel() from a button handler, etc.

30.5 Async in UI Apps

Private Async Sub btnLoad_Click(sender As Object, e As EventArgs) Handles btnLoad.Click
    btnLoad.Enabled = False
    Try
        lblStatus.Text = "Loading..."
        Dim data = Await Task.Run(Function() LoadDataFromDisk())    ' the UI stays responsive
        dgvData.DataSource = data                                   ' back on the UI thread automatically
        lblStatus.Text = "Done"
    Catch ex As Exception
        MessageBox.Show(ex.Message)
    Finally
        btnLoad.Enabled = True
    End Try
End Sub

30.6 Async Best Practices

"Async all the way": avoid .Result / .Wait() in UI or ASP.NET code (they cause deadlocks).

Use ConfigureAwait(False) in library code. Avoid Async Sub except for event handlers.

Name async methods with an Async suffix. Pass CancellationTokens through.