Async/Await

Asynchronous programming lets your app do other work while waiting for slow operations (network, disk, database) instead of blocking the thread.

Core Concepts

  • async — marks a method as asynchronous
  • await — pauses execution until the awaited task completes
  • Task — represents an asynchronous operation (void return)
  • Task<T> — represents an async operation that returns a value

Basic Example

public static async Task<string> FetchDataAsync(string url)
{
    using var client = new HttpClient();
    string content = await client.GetStringAsync(url);
    return content;
}

// Calling async code
string html = await FetchDataAsync("https://example.com");
Console.WriteLine($"Received {html.Length} characters");

Multiple Async Operations

// Sequential — one after another
string page1 = await FetchDataAsync("https://api.example.com/1");
string page2 = await FetchDataAsync("https://api.example.com/2");

// Parallel — both at once (faster!)
Task<string> task1 = FetchDataAsync("https://api.example.com/1");
Task<string> task2 = FetchDataAsync("https://api.example.com/2");
string[] results = await Task.WhenAll(task1, task2);

Async File I/O

// Reading
string content = await File.ReadAllTextAsync("data.txt");

// Writing
await File.WriteAllTextAsync("output.txt", "Hello async world!");

// Reading lines
string[] lines = await File.ReadAllLinesAsync("log.txt");

Common Pitfalls

1. Async void — avoid it:

// BAD — exceptions are unobservable
async void DoWork() { ... }

// GOOD — return Task
async Task DoWorkAsync() { ... }

Only use async void for event handlers.

2. Blocking on async code — causes deadlocks:

// BAD — can deadlock in UI/ASP.NET
var result = FetchDataAsync(url).Result;

// GOOD — await it
var result = await FetchDataAsync(url);

3. Not using ConfigureAwait in libraries:

// In library code, avoid capturing sync context
var data = await client.GetStringAsync(url)
    .ConfigureAwait(false);