C#  

How to Use Async and Await in C#

Introduction

In modern C# development, writing responsive and high-performance applications is very important. Whether you are building web applications, APIs, or desktop software, handling long-running operations efficiently is critical. This is where async and await in C# come into play.

Async and await help you write asynchronous code in a simple and readable way. Instead of blocking the main thread, they allow your application to continue running while waiting for tasks like database calls, file operations, or API requests.

In this article, we will explain how to use async and await in C# in simple words, understand how they work internally, and explore best practices with real-world examples.

What is Asynchronous Programming in C#?

Asynchronous programming means executing tasks without blocking the main thread.

In simple words, your application can do other work while waiting for a task to complete.

Example Without Async

public void GetData()
{
    var data = FetchDataFromServer(); // Blocks thread
    Console.WriteLine(data);
}

Here, the application waits until the data is fetched.

Example With Async

public async Task GetDataAsync()
{
    var data = await FetchDataFromServerAsync();
    Console.WriteLine(data);
}

Now, the thread is not blocked while waiting.

What is async in C#?

The async keyword is used to define a method as asynchronous.

Key Points

  • It allows the use of await inside the method

  • It usually returns Task, Task, or void (for event handlers)

Example

public async Task<string> GetMessageAsync()
{
    return "Hello Async";
}

What is await in C#?

The await keyword is used to pause the execution of an async method until the awaited task is complete.

Key Points

  • It works only inside async methods

  • It does not block the thread

  • It resumes execution after task completion

Example

public async Task ProcessAsync()
{
    await Task.Delay(2000);
    Console.WriteLine("Task completed");
}

How async and await Work Internally

Behind the scenes, async and await use Task-based asynchronous programming.

  • The method starts execution

  • When await is reached, control returns to the caller

  • The task runs in the background

  • Once completed, execution resumes

This improves performance and responsiveness.

Return Types in Async Methods

1. Task

Used when no value is returned.

public async Task DoWorkAsync()
{
    await Task.Delay(1000);
}

2. Task

Used when a value is returned.

public async Task<int> GetNumberAsync()
{
    await Task.Delay(1000);
    return 10;
}

3. void (Avoid if Possible)

Used only for event handlers.

public async void Button_Click(object sender, EventArgs e)
{
    await Task.Delay(1000);
}

Real-World Example: Calling an API

public async Task<string> GetApiDataAsync()
{
    using (HttpClient client = new HttpClient())
    {
        var response = await client.GetAsync("https://api.example.com/data");
        return await response.Content.ReadAsStringAsync();
    }
}

This allows non-blocking API calls.

Benefits of Using Async and Await in C#

  • Improves application responsiveness

  • Better performance for I/O operations

  • Easy to write and read compared to callbacks

  • Efficient use of system resources

Common Mistakes to Avoid

1. Blocking Async Code

var result = GetDataAsync().Result; // Avoid

This can cause deadlocks.

2. Not Using Await

GetDataAsync(); // Missing await

Task may not complete as expected.

3. Overusing Async

Do not use async for CPU-bound tasks unnecessarily.

Async vs Parallel Programming

FeatureAsync/AwaitParallel Programming
PurposeI/O-bound tasksCPU-bound tasks
Thread UsageMinimal threadsMultiple threads
ExampleAPI calls, DB queriesData processing

When to Use Async and Await in C#

Use async and await when:

  • Calling APIs or web services

  • Accessing databases

  • Reading/writing files

  • Performing network operations

Best Practices for Async Programming

1. Use Async All the Way

Avoid mixing sync and async code.

2. Use ConfigureAwait(false) (Advanced)

Improves performance in library code.

3. Handle Exceptions Properly

try
{
    await DoWorkAsync();
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}

4. Avoid Async Void

Except for event handlers.

Real-World Scenario

In a web application:

  • Multiple users send requests

  • Async APIs handle requests without blocking threads

  • Server handles more users efficiently

Summary

Async and await in C# are powerful features that help developers write non-blocking, efficient, and scalable applications. They simplify asynchronous programming and improve application performance, especially for I/O-bound operations like API calls and database queries. By following best practices and avoiding common mistakes, you can fully utilize async and await to build modern, high-performance applications.