Skip to content

Bits of .NET

Daily micro-tips for C#, SQL, performance, and scalable backend engineering.

  • Asp.Net Core
  • C#
  • SQL
  • JavaScript
  • CSS
  • About
  • ErcanOPAK.com
  • No Access
  • Privacy Policy
C#

C#: Async/Await Best Practices for Web APIs

- 15.08.26 - ErcanOPAK

⚡ Async/Await = Scalable APIs

Web APIs need to scale. Async/Await best practices ensure your APIs handle high load efficiently.

📝 API Best Practices

// Async Controllers
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    private readonly IOrderService _orderService;

    public OrdersController(IOrderService orderService)
    {
        _orderService = orderService;
    }

    [HttpGet("{id}")]
    public async Task> GetOrder(int id)
    {
        var order = await _orderService.GetOrderAsync(id);
        if (order == null)
            return NotFound();
        return Ok(order);
    }

    [HttpPost]
    public async Task> CreateOrder(OrderDto dto)
    {
        var order = await _orderService.CreateOrderAsync(dto);
        return CreatedAtAction(nameof(GetOrder), new { id = order.Id }, order);
    }
}

// Async Service Implementation
public class OrderService : IOrderService
{
    private readonly IOrderRepository _orderRepo;
    private readonly IEmailService _emailService;

    public async Task GetOrderAsync(int id)
    {
        return await _orderRepo.GetOrderWithDetailsAsync(id);
    }

    public async Task CreateOrderAsync(OrderDto dto)
    {
        var order = new Order { /* ... */ };
        await _orderRepo.AddAsync(order);
        await _orderRepo.SaveAsync();
        
        // Fire and forget (not recommended for critical operations)
        _ = _emailService.SendConfirmationAsync(order);
        
        return order;
    }
}

🎯 Performance Patterns

// Parallel API Calls
[HttpGet("dashboard")]
public async Task> GetDashboard()
{
    var usersTask = _userService.GetUsersAsync();
    var ordersTask = _orderService.GetOrdersAsync();
    var statsTask = _statsService.GetStatsAsync();
    
    await Task.WhenAll(usersTask, ordersTask, statsTask);
    
    return new DashboardData
    {
        Users = usersTask.Result,
        Orders = ordersTask.Result,
        Stats = statsTask.Result
    };
}

// Proper Cancellation
public async Task>> SearchOrders(
    [FromQuery] string query,
    CancellationToken cancellationToken)
{
    return Ok(await _orderService.SearchOrdersAsync(query, cancellationToken));
}

// Timeout Handling
public async Task> GetExternalData()
{
    using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
    try
    {
        return Ok(await _externalService.GetDataAsync(cts.Token));
    }
    catch (OperationCanceledException)
    {
        return StatusCode(408, "Request timed out");
    }
}

// Rate Limiting
public async Task> CreateOrderWithLimit(OrderDto dto)
{
    if (!await _rateLimiter.IsAllowedAsync(User.Identity.Name))
    {
        return StatusCode(429, "Too many requests");
    }
    
    return await CreateOrderAsync(dto);
}

💡 Web API Tips

  • Use async all the way
  • Implement proper cancellation
  • Set appropriate timeouts
  • Use parallel operations when possible
  • Implement rate limiting

Async/await best practices are essential for building scalable web APIs. They ensure your APIs perform well under load.

— API Performance Engineer

Related posts:

C# Async Void Is Dangerous

C# Memory Leak: Event Handlers Never Unsubscribe

Why BackgroundServices Die Silently in Production

Post Views: 3

Post navigation

.NET Core: Health Checks for Application Monitoring
C#: LINQ Performance Optimization Techniques

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

October 2026
M T W T F S S
 1234
567891011
12131415161718
19202122232425
262728293031  
« Sep    

Most Viewed Posts

  • Get the User Name and Domain Name from an Email Address in SQL (973)
  • How to make theater mode the default for Youtube (952)
  • How to add default value for Entity Framework migrations for DateTime and Bool (939)
  • Get the First and Last Word from a String or Sentence in SQL (847)
  • How to select distinct rows in a datatable in C# (837)
  • How to enable, disable and check if Service Broker is enabled on a database in SQL Server (624)
  • Add Constraint to SQL Table to ensure email contains @ (590)
  • Average of all values in a column that are not zero in SQL (553)
  • How to use Map Mode for Vertical Scroll Mode in Visual Studio (526)
  • Find numbers with more than two decimal places in SQL (468)

Recent Posts

  • CSS: Fix a prefers-color-scheme Media Query That Gets Silently Overridden by a Browser Extension’s Forced Dark Mode
  • Git: Fix a Merge Commit That Silently Drops a File Because Both Branches Deleted It Differently
  • HTML5: Fix a Native Lazy-Loading Image That Never Loads Because It Sits Inside a Hidden Tab Until the User Clicks It
  • The AI Prompt That Traces a Null Reference Exception Back to the Exact Line That First Produced the Null
  • The AI Prompt That Turns a Gym Membership Contract’s Fine Print Into a Plain-English List of Cancellation Steps
  • Photoshop: Fix a Color Profile Mismatch That Makes Printed Output Look Nothing Like What You Saw On Screen
  • WordPress: Fix Search Results That Return Pages From a Theme You Deactivated Months Ago
  • Visual Studio: Fix a Test Project That Builds Fine Alone but Fails to Discover Any Tests After a NuGet Restore
  • ASP.NET Core: Fix a File Upload That Times Out on Slow Connections Only Because Kestrel’s Minimum Data Rate Feature Kicked In
  • JavaScript: Fix an Array Destructuring Default Value That Silently Never Applies Because null Was Passed Instead of Undefined

Most Viewed Posts

  • Get the User Name and Domain Name from an Email Address in SQL (973)
  • How to make theater mode the default for Youtube (952)
  • How to add default value for Entity Framework migrations for DateTime and Bool (939)
  • Get the First and Last Word from a String or Sentence in SQL (847)
  • How to select distinct rows in a datatable in C# (837)

Recent Posts

  • CSS: Fix a prefers-color-scheme Media Query That Gets Silently Overridden by a Browser Extension’s Forced Dark Mode
  • Git: Fix a Merge Commit That Silently Drops a File Because Both Branches Deleted It Differently
  • HTML5: Fix a Native Lazy-Loading Image That Never Loads Because It Sits Inside a Hidden Tab Until the User Clicks It
  • The AI Prompt That Traces a Null Reference Exception Back to the Exact Line That First Produced the Null
  • The AI Prompt That Turns a Gym Membership Contract’s Fine Print Into a Plain-English List of Cancellation Steps

Social

  • ErcanOPAK.com
  • GoodReads
  • LetterBoxD
  • Linkedin
  • The Blog
  • Twitter
© 2026 Bits of .NET | Built with Xblog Plus free WordPress theme by wpthemespace.com