Async & Await
async/await models asynchronous I/O without blocking threads — critical for ASP.NET Core scalability.
Introduction
async/await models asynchronous I/O without blocking threads — critical for ASP.NET Core scalability. async methods return Task or Task<T>; await suspends until completion, freeing the thread for other requests.
Interviewers hammer ConfigureAwait, deadlock from .Result, ValueTask, and IAsyncEnumerable streaming. Never block on async code in web apps.
The story
A product catalog page loads names for twenty items from a REST API. Firing twenty sequential HTTP calls would take twenty round trips; Task.WhenAll runs them concurrently so the page renders as fast as the slowest single request — critical for ASP.NET Core APIs that must not block threads waiting on I/O.
Understanding the topic
Key concepts
- async method returns Task/Task
/void (avoid async void except handlers). - await captures context optionally; ConfigureAwait(false) in libraries.
- Task.Run offloads CPU work to thread pool.
- ValueTask reduces allocation for hot paths.
- CancellationToken propagates cancel through async chain.
- IAsyncEnumerable
async streams with await foreach.
sequenceDiagramCaller->>AsyncMethod: await TaskAsyncMethod->>ThreadPool: schedule continuationThreadPool->>IO: network / diskIO-->>AsyncMethod: completeAsyncMethod-->>Caller: result
Step-by-step explanation
- Compiler rewrites async method to state machine.
- await incomplete Task registers continuation.
- Thread returns to pool until I/O completes.
- SynchronizationContext resumes UI thread in desktop apps.
- Exception stored in Task; thrown on await.
- Parallel async: Task.WhenAll coordinates multiple.
Practical code example
Async API client with cancellation and WhenAll parallel fetch:
namespace TechLearningPro.AsyncAwait;public sealed class CatalogClient(HttpClient http){public async Task<IReadOnlyList<string>> GetProductNamesAsync(IEnumerable<Guid> ids,CancellationToken ct){var tasks = ids.Select(id =>http.GetStringAsync(quot;/api/products/{id}/name", ct));var names = await Task.WhenAll(tasks);return names.ToList();}public async IAsyncEnumerable<string> StreamNamesAsync(IEnumerable<Guid> ids,[EnumeratorCancellation] CancellationToken ct){foreach (var id in ids){ct.ThrowIfCancellationRequested();yield return await http.GetStringAsync(quot;/api/products/{id}/name", ct);}}}
Line-by-line code explanation
CatalogClient(HttpClient http)receives a typed HTTP client from dependency injection.GetProductNamesAsync(..., CancellationToken ct)propagates cancellation through the async chain.ids.Select(id => http.GetStringAsync(...))starts one async HTTP task per product ID.await Task.WhenAll(tasks)waits for every parallel request to complete.names.ToList()materializes the string array into a list for the return type.IAsyncEnumerable<string> StreamNamesAsyncstreams names one at a time for large catalogs.[EnumeratorCancellation] CancellationToken ctwires cancellation into async iterators.ct.ThrowIfCancellationRequested()checks cancellation before each iteration.yield return await http.GetStringAsync(...)emits each name as it arrives without buffering all.
Key takeaway: WhenAll parallelizes I/O-bound calls. IAsyncEnumerable streams results without loading all at once. EnumeratorCancellation wires token.
Real-world use
Where you'll use this in production
- ASP.NET Core controllers awaiting EF and HTTP.
- Background services with PeriodicTimer.
- File and cloud blob async uploads.
- gRPC streaming responses.
Best practices
- Async all the way — no sync-over-async.
- Pass CancellationToken through layers.
- Use Task.WhenAll for independent I/O parallelism.
- ConfigureAwait(false) in library code.
- Prefer await using for async disposal.
Common mistakes
- .Result or .Wait() deadlocks with SynchronizationContext.
- async void swallows exceptions in event handlers carelessly.
- Task.Run in ASP.NET for normal request I/O — unnecessary.
- Creating new HttpClient per request — use IHttpClientFactory.
Advanced interview questions
Q1BeginnerWhat does await do?
Q2BeginnerTask vs ValueTask?
Q3IntermediateWhy ConfigureAwait(false)?
Q4IntermediateTask.WhenAll vs Parallel.ForEach?
Q5AdvancedImplement timeout wrapper for any Task.
Summary
async/await enables scalable non-blocking I/O. Never block async with Wait/Result in ASP.NET. Propagate CancellationToken; use WhenAll for parallel I/O. IAsyncEnumerable streams async sequences. Next: dependency injection in ASP.NET Core.