ASP.NET Core  

Building API Rate Limiting in ASP.NET Core Using .NET Built-In Middleware

Introduction

Modern web APIs must handle traffic responsibly. Without protection, a single misbehaving client can overload your server, impact performance, or even cause downtime. Traditionally, developers relied on third-party libraries or API gateways for rate limiting.

Starting with .NET 7+, ASP.NET Core introduced first-class rate limiting middleware, making it easier than ever to control request flow directly inside your application.

In this article, we’ll explore:

  • What rate limiting is

  • Why built-in rate limiting matters

  • How to implement rate limiting in ASP.NET Core

  • Practical examples with policies

What Is Rate Limiting?

Rate limiting restricts how many requests a client can make within a specific time window.

Examples:

  • 100 requests per minute per user

  • 10 login attempts per minute per IP

  • Unlimited requests for internal services

Rate limiting helps:

  • Prevent abuse and brute-force attacks

  • Improve API stability

  • Ensure fair usage across clients

Why Use Built-In Rate Limiting in .NET?

The built-in rate limiter in ASP.NET Core offers:

  • High performance (uses System.Threading.RateLimiting)

  • No external dependencies

  • Tight integration with middleware pipeline

  • Policy-based configuration

This makes it production-ready and easy to maintain.

Adding Rate Limiting to an ASP.NET Core API

Step 1: Create a New Web API

dotnet new webapi -n RateLimitDemo

Step 2: Configure Rate Limiting in Program.cs

using System.Threading.RateLimiting;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter("FixedPolicy", limiterOptions =>
    {
        limiterOptions.Window = TimeSpan.FromMinutes(1);
        limiterOptions.PermitLimit = 5;
        limiterOptions.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        limiterOptions.QueueLimit = 2;
    });

    options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
});

builder.Services.AddControllers();

var app = builder.Build();

app.UseRateLimiter();

app.MapControllers();

app.Run();

Understanding the Configuration

SettingDescription
PermitLimitNumber of allowed requests
WindowTime duration
QueueLimitRequests waiting when limit is exceeded
Status429HTTP response for blocked requests

Step 3: Apply Rate Limiting to a Controller

using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/test")]
public class TestController : ControllerBase
{
    [HttpGet]
    [EnableRateLimiting("FixedPolicy")]
    public IActionResult Get()
    {
        return Ok("Request processed successfully.");
    }
}

Now:

  • First 5 requests per minute succeed

  • Further requests receive HTTP 429—Too Many Requests

Using Different Rate Limiting Strategies

ASP.NET Core supports multiple limiter types:

1. Fixed Window

Good for simple limits (e.g., per minute).

2. Sliding Window

More accurate, smooth traffic control.

3. Token Bucket

Ideal for burst traffic.

4. Concurrency Limiter

Limits simultaneous requests.

Example (Concurrency Limiter):

options.AddConcurrencyLimiter("ConcurrentPolicy", opt =>
{
    opt.PermitLimit = 3;
    opt.QueueLimit = 5;
});

Applying Rate Limiting Globally

You can apply rate limiting to all endpoints:

app.MapControllers()
   .RequireRateLimiting("FixedPolicy");

This is useful for public APIs.

Real-World Use Cases

  • Login & OTP endpoints

  • Public APIs

  • Payment gateways

  • Search APIs

  • Report downloads

Best Practices

✔ Use stricter limits for sensitive endpoints
✔ Combine with authentication and logging
✔ Monitor HTTP 429 responses
✔ Adjust limits based on real traffic

Conclusion

Rate limiting is no longer an advanced feature reserved for gateways and proxies. With modern .NET, you can implement high-performance, policy-based rate limiting directly in your ASP.NET Core applications—cleanly and efficiently.

By using the built-in middleware, you gain better control, improved security, and simpler architecture without external dependencies.