Public APIs are constantly exposed to unpredictable traffic. A sudden spike in legitimate requests, an aggressive web crawler, or a malicious bot can overwhelm application resources and degrade performance for every user. Without proper request throttling, APIs may experience increased latency, excessive infrastructure costs, or even complete service outages.
ASP.NET Core includes a built-in Rate Limiting middleware that allows developers to control how many requests clients can make over a specific period. By applying appropriate rate limiting policies, applications can protect backend services, improve fairness among users, and maintain consistent performance under heavy load.
Rather than relying solely on external API gateways, this article explains how to implement production-ready rate limiting directly in ASP.NET Core.
Note: Rate limiting is not a replacement for authentication, authorization, or DDoS protection. It is one layer of a broader API security strategy.
Why Rate Limiting Matters
Without rate limiting, applications may encounter:
API abuse
Bot traffic
Denial-of-service attempts
Database overload
Excessive cloud costs
Poor user experience during traffic spikes
Limiting request rates helps maintain predictable application performance.
Common Rate Limiting Algorithms
ASP.NET Core supports several algorithms.
| Algorithm | Best For |
|---|---|
| Fixed Window | Simple APIs |
| Sliding Window | Public APIs |
| Token Bucket | Burst traffic |
| Concurrency Limiter | Long-running requests |
Each algorithm balances fairness, performance, and implementation complexity differently.
Rate Limiting Architecture
flowchart LR
A[Client]
B[Rate Limiter]
C{Limit Exceeded?}
D[ASP.NET Core API]
E[(Database)]
A --> B
B --> C
C -->|No| D
D --> E
C -->|Yes| F[HTTP 429 Too Many Requests]
Every incoming request passes through the rate limiter before reaching the application.
Installing the Middleware
Register rate limiting during application startup.
builder.Services.AddRateLimiter(options =>
{
});
Enable the middleware.
var app = builder.Build();
app.UseRateLimiter();
app.MapControllers();
app.Run();
The middleware processes requests before controller actions execute.
Configuring a Fixed Window Policy
A fixed window policy allows a specific number of requests during a defined time period.
builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter(
"fixed",
limiterOptions =>
{
limiterOptions.PermitLimit = 100;
limiterOptions.Window =
TimeSpan.FromMinutes(1);
limiterOptions.QueueLimit = 0;
});
});
This policy permits up to 100 requests per minute.
Applying a Rate Limit
Apply the policy to an endpoint.
app.MapGet("/products", GetProducts)
.RequireRateLimiting("fixed");
Only requests to this endpoint are subject to the configured policy.
Using a Sliding Window
Sliding windows distribute requests more evenly.
builder.Services.AddRateLimiter(options =>
{
options.AddSlidingWindowLimiter(
"sliding",
limiterOptions =>
{
limiterOptions.PermitLimit = 100;
limiterOptions.Window =
TimeSpan.FromMinutes(1);
limiterOptions.SegmentsPerWindow = 6;
});
});
This approach reduces sudden bursts at window boundaries.
Using a Token Bucket
Token Bucket is ideal for bursty traffic.
builder.Services.AddRateLimiter(options =>
{
options.AddTokenBucketLimiter(
"token",
limiterOptions =>
{
limiterOptions.TokenLimit = 200;
limiterOptions.TokensPerPeriod = 20;
limiterOptions.ReplenishmentPeriod =
TimeSpan.FromSeconds(10);
});
});
Clients can consume available tokens quickly, while new tokens are replenished over time.
Join the conversation! Your thoughts help the community grow.