SyntaxStudy
Sign Up
C# Async and Await Fundamentals
C# Beginner 1 min read

Async and Await Fundamentals

C#'s async/await feature, built on top of the Task Parallel Library, lets you write asynchronous code that reads almost identically to synchronous code. An `async` method returns `Task` (no result), `Task` (with result), or `ValueTask` (for performance-sensitive hot paths that often complete synchronously). When the runtime hits an `await` expression it suspends the current method and returns control to the caller — without blocking the thread. When the awaited operation completes, execution resumes after the `await`. This non-blocking model is ideal for I/O-bound work: network calls, file reads, database queries. Async methods should be awaited all the way up the call chain — avoid mixing `async` with `.Result` or `.Wait()` as this can cause deadlocks, especially in UI and ASP.NET contexts. The one acceptable exception is at the top-level entry point or in `Main` (which can be `async Task Main`).
Example
// async/await fundamentals with HttpClient

using System.Net.Http;
using System.Net.Http.Json;

// async Main — entry point can be async in modern C#
// (the compiler wraps it in a Task automatically with top-level statements)

var client = new HttpClient();
client.DefaultRequestHeaders.UserAgent.ParseAdd("CsharpDemo/1.0");

// Async method returning Task<T>
static async Task<string> FetchAsync(HttpClient http, string url)
{
    HttpResponseMessage response = await http.GetAsync(url);
    response.EnsureSuccessStatusCode();
    return await response.Content.ReadAsStringAsync();
}

// Awaiting the result
try
{
    string body = await FetchAsync(client, "https://httpbin.org/get");
    Console.WriteLine(body[..200]); // first 200 chars
}
catch (HttpRequestException ex)
{
    Console.WriteLine($"HTTP error: {ex.StatusCode} — {ex.Message}");
}

// Running multiple async operations concurrently with Task.WhenAll
async Task<int[]> FetchCountsAsync()
{
    var urls = new[]
    {
        "https://httpbin.org/get",
        "https://httpbin.org/ip"
    };

    Task<string>[] tasks = urls
        .Select(url => FetchAsync(client, url))
        .ToArray();

    string[] results = await Task.WhenAll(tasks);
    return results.Select(r => r.Length).ToArray();
}

int[] counts = await FetchCountsAsync();
Console.WriteLine($"Response sizes: {string.Join(", ", counts)}");