Public APIs are constantly exposed to unpredictable traffic. Whether it's accidental overuse, poorly designed client applications, or malicious attacks, excessive requests can degrade performance, increase infrastructure costs, and even make an application unavailable.
Rate limiting helps protect APIs by controlling how many requests a client can make within a specified period. Starting with .NET 7, ASP.NET Core includes built-in rate limiting middleware, making it easier to implement robust traffic control without relying on third-party libraries.
In this article, you'll learn how rate limiting works, explore the available algorithms, and discover best practices for building secure and scalable ASP.NET Core APIs.
Why Rate Limiting Matters
Consider a public product API that receives thousands of requests from different clients.
Without rate limiting:
Clients
│
ASP.NET Core API
│
Database
A single client could send excessive requests, consuming server resources and affecting other users.
With rate limiting:
Clients
│
Rate Limiter
│
ASP.NET Core API
│
Database
The application accepts requests within defined limits while rejecting excessive traffic with an HTTP 429 Too Many Requests response.
Rate limiting helps:
Protect server resources
Prevent abuse
Improve application stability
Ensure fair usage among clients
Reduce the impact of denial-of-service attempts
Built-In Rate Limiting Middleware
ASP.NET Core includes rate limiting middleware in the Microsoft.AspNetCore.RateLimiting package.
Register rate limiting during application startup:
using System.Threading.RateLimiting;
builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter("fixed", limiter =>
{
limiter.PermitLimit = 100;
limiter.Window = TimeSpan.FromMinutes(1);
});
});
Enable the middleware:
app.UseRateLimiter();
Apply the policy to an endpoint:
app.MapGet("/products", () => Results.Ok())
.RequireRateLimiting("fixed");
This configuration limits clients to 100 requests per minute for the protected endpoint.
Fixed Window Rate Limiting
The fixed window algorithm divides time into fixed intervals.
Example:
Window: 1 minute
Limit: 100 requests
A client can make up to 100 requests during the current minute. Once the limit is reached, additional requests are rejected until the next window begins.
Best Use Cases
Public REST APIs
Simple application throttling
Low-complexity workloads
Its simplicity makes it easy to configure, although it can allow request bursts at window boundaries.
Sliding Window Rate Limiting
Sliding window limiting distributes requests more evenly over time.
Instead of resetting all counters simultaneously, it continuously evaluates activity over the most recent time period.
Benefits include:
Smoother request distribution
Reduced traffic spikes
More consistent resource utilization
This approach is often preferable for APIs with fluctuating traffic.
Token Bucket Algorithm
The token bucket algorithm provides greater flexibility.
Tokens are added to a bucket at a fixed rate.
Each incoming request consumes one token.
If tokens remain:
Request succeeds.
If no tokens remain:
Request is rejected.
This algorithm allows short traffic bursts while maintaining an average request rate.
It's commonly used for public APIs that experience occasional spikes in demand.
Concurrency Limiting
Some operations are expensive regardless of request frequency.
Concurrency limiting controls how many requests execute simultaneously.
Example configuration:
builder.Services.AddRateLimiter(options =>
{
options.AddConcurrencyLimiter("concurrent", limiter =>
{
limiter.PermitLimit = 20;
});
});
Only 20 requests are processed concurrently, while additional requests wait or are rejected depending on the configuration.
This strategy works well for resource-intensive endpoints.
Choosing a Partition Key
Rate limiting policies are typically applied per client rather than globally.
Join the conversation! Your thoughts help the community grow.