Skip to main content

How to write asynchronous C# with async and await

Write asynchronous C#: define async methods returning Task, await without blocking, run work concurrently with Task.WhenAll, support cancellation tokens, and avoid common async pitfalls.

Difficulty
Intermediate
Duration
45 minutes
Steps
6

How async and await work in C#

C# models asynchronous work with the Task type and the async and await keywords. An await suspends the method until the awaited task completes, freeing the thread to do other work instead of blocking. This is ideal for I/O such as network and disk, letting a server handle many requests with few threads.

Prerequisites

  • A recent .NET SDK
  • Comfort with basic C# syntax

Steps

1. Write an async method

Mark the method async and return Task or Task<T>.

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

2. Await without blocking

Use await to get the result. Avoid .Result or .Wait(), which block the thread and can deadlock.

string body = await FetchAsync("https://example.com");

3. Run tasks concurrently with WhenAll

Start tasks without awaiting each immediately, then await them together.

var tasks = urls.Select(FetchAsync);
string[] bodies = await Task.WhenAll(tasks);

This runs the requests concurrently rather than one after another.

4. Cancel with CancellationToken

Accept a CancellationToken and pass it down so callers can cancel.

async Task WorkAsync(CancellationToken ct)
{
    await Task.Delay(1000, ct);
}

5. Handle exceptions in async code

Exceptions from awaited tasks surface at the await, so wrap it in try-catch as usual.

try { await FetchAsync(url); }
catch (HttpRequestException ex) { Log(ex); }

6. Avoid common async pitfalls

Do not use async void except for event handlers; prefer async Task. Do not block on async code. Flow the cancellation token through the whole call chain.

Verification

Write a method that fetches several URLs sequentially, then with Task.WhenAll, and time both. Confirm the concurrent version is faster. Cancel a long delay with a token and confirm an OperationCanceledException is raised.

Next Steps

Explore IAsyncEnumerable for async streams, ValueTask for hot paths, ConfigureAwait in libraries, and Channel<T> for producer-consumer pipelines.

Prerequisites

  • .NET SDK installed
  • Basic C# syntax

Steps

  • 1
    Write an async method
  • 2
    Await without blocking
  • 3
    Run tasks concurrently with WhenAll
  • 4
    Cancel with CancellationToken
  • 5
    Handle exceptions in async code
  • 6
    Avoid common async pitfalls