-
Notifications
You must be signed in to change notification settings - Fork 2
CSharp AsyncAwait Basics
This lesson introduces the core principles of using async and await for asynchronous programming in C#. Asynchronous operations are crucial for responsive and scalable applications, especially for long-running operations like network calls or file I/O.
Related wiki pages:
- General C# topics:
CSharpBible.md - Libraries and tasks:
CSharpBible-Libraries.md - Async in MVVM / GUI:
CSharpBible-MVVM-Standard.md,Avalonia-Apps.md,GUI_Window.md
Official documentation:
- Async overview: https://learn.microsoft.com/dotnet/csharp/asynchronous-programming/
-
asyncandawait: https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/async
Asynchronous programming lets your program start an operation and continue doing other work while waiting for the result (e.g., I/O, network, timers).
-
asyncmarks a method as asynchronous and allows the use ofawaitinside it. -
awaitasynchronously waits for aTaskto complete without blocking the current thread.
Contrary to some misconceptions:
- There is no magical "event" called
AwaitableEventyou must manage yourself – the C# compiler and .NET runtime handle the state machine behindasync/await. - Asynchronous methods usually return
TaskorTask<T>(orValueTask/ValueTask<T>), which represent the ongoing operation.
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Starting...");
try
{
await ProcessDataAsync("example payload");
}
catch (Exception ex)
{
Console.Error.WriteLine($"Error: {ex.Message}");
}
Console.WriteLine("Finished. Press any key to exit...");
Console.ReadKey();
}
static async Task ProcessDataAsync(string data)
{
Console.WriteLine($"Processing data: {data}");
// Simulate an I/O-bound operation
await Task.Delay(2000); // non-blocking 2 second delay
Console.WriteLine("Processing complete.");
}
}Key points:
-
static async Task Mainis supported in modern C# (.NET Core / .NET 5+). -
await Task.Delay(2000)does not block the thread; it returns control until the delay completes. - Exceptions inside
ProcessDataAsyncpropagate toMainand can be caught there.
Typical async method signatures:
-
Task– asynchronous method that does not produce a result -
Task<T>– asynchronous method that returns a result of typeT
Example with a result:
static async Task<int> CalculateLengthAsync(string value)
{
await Task.Delay(500); // simulate work
return value.Length;
}
static async Task DemoAsync()
{
int length = await CalculateLengthAsync("Hello");
Console.WriteLine($"Length: {length}");
}You should usually return Task/Task<T> instead of blocking on them (.Result or .Wait()), especially in UI or ASP.NET code, to avoid deadlocks.
For more patterns around tasks and libraries, see CSharpBible-Libraries.md.
- HTTP calls and web APIs (
HttpClient.GetAsync, etc.) - Reading/writing files (
FileStream.ReadAsync,File.ReadAllTextAsync) - Database queries (e.g.
DbCommand.ExecuteReaderAsync) - Timers and background work (
Task.Delay,PeriodicTimer)
These are often combined with MVVM view models and commands (see CSharpBible-MVVM-Standard.md and CommunityToolkit.MVVM.md).
- Prefer
asyncall the way: avoid mixing blocking and async (no.Result/.Wait()on tasks). - Use
Task.Delayinstead ofThread.Sleepin async code. - Handle exceptions with
try/catch(seeCSharp-Exceptions-TryCatch.md). - For library code, consider
ConfigureAwait(false)where you do not need the original synchronization context.
- Read the official async/await docs linked above.
- Try converting a synchronous I/O method to an async version.
- Combine this with LINQ from
CSharp-LINQ-Where-OrderBy.mdfor processing result collections asynchronously.