Introduction

In modern web applications, performance and scalability are critical. When handling API requests, blocking operations (like database queries or external service calls) can slow down the entire system.

ASP.NET Core provides async/await support to make applications more responsive by freeing up threads while waiting for I/O operations. This allows the server to handle more requests concurrently.

Why async/await?

Example: Customer API with Database Access

Imagine you’re building a Customer Management API that fetches customer data from a database. Without async/await, the request thread would block until the database query completes. With async/await, the thread is released back to the pool, improving efficiency.

Step 1: Define the Model

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
}

Step 2: Create the DbContext

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

    public DbSet<Customer> Customers { get; set; }
}

Step 3: Implement Repository with Async Methods

public interface ICustomerRepository
{
    Task<IEnumerable<Customer>> GetAllAsync();
    Task<Customer> GetByIdAsync(int id);
}

public class CustomerRepository : ICustomerRepository
{
    private readonly AppDbContext _context;

    public CustomerRepository(AppDbContext context)
    {
        _context = context;
    }

    public async Task<IEnumerable<Customer>> GetAllAsync()
    {
        return await _context.Customers.AsNoTracking().ToListAsync();
    }

    public async Task<Customer> GetByIdAsync(int id)
    {
        return await _context.Customers.FindAsync(id);
    }
}

Step 4: Inject Repository into Controller

[ApiController]
[Route("api/[controller]")]
public class CustomersController : ControllerBase
{
    private readonly ICustomerRepository _repository;

    public CustomersController(ICustomerRepository repository)
    {
        _repository = repository;
    }

    [HttpGet]
    public async Task<IActionResult> GetAll()
    {
        var customers = await _repository.GetAllAsync();
        return Ok(customers);
    }

    [HttpGet("{id}")]
    public async Task<IActionResult> GetById(int id)
    {
        var customer = await _repository.GetByIdAsync(id);
        if (customer == null) return NotFound();
        return Ok(customer);
    }
}

Example in Action

This ensures the server can handle many concurrent requests without being blocked by slow database calls.

Practices for async/await in APIs

Conclusion

Using async/await in ASP.NET Core APIs prevents blocking requests, improves scalability, and enhances responsiveness. Our Customer API example shows how async methods integrate seamlessly with EF Core and controllers, making applications more efficient under load.