Ever noticed how a sudden traffic spike can bring your API to a halt?
Why Distributed Rate Limiting Matters
In micro‑service environments a single instance cannot reliably enforce request caps when the load is shared across multiple nodes. Without a coordinated strategy, attackers can bypass limits by targeting different pods, and legitimate users suffer inconsistent throttling. A distributed store such as Redis guarantees that every request checks the same counter, keeping the policy uniform across the whole cluster.
Prerequisites and System Requirements
You need .NET 8 SDK, a running Redis server (minimum version 6.0), and the AspNetCoreRateLimit NuGet package. The Redis instance should be reachable from all API nodes; for local testing Docker provides a quick setup:
docker run -d --name redis-rate -p 6379:6379 redis:6-alpine Adding Redis to a .NET 8 Minimal API
Register the StackExchange.Redis cache early in the builder pipeline so that the rate‑limiting services can reuse it.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddStackExchangeRedisCache(options => {
options.Configuration = "localhost:6379";
options.InstanceName = "RateLimitRedis_";
}); Installing AspNetCoreRateLimit
Run the following command in the project folder. The package includes both IP‑based and client‑ID based policies.
dotnet add package AspNetCoreRateLimit Configuring Rate Limiting Options
Create an appsettings.json section that defines a general rule of 100 requests per minute for every endpoint. The same file can host client‑specific limits if needed.
{
"IpRateLimiting": {
"EnableEndpointRateLimiting": true,
"StackBlockedRequests": false,
"RealIpHeader": "X-Real-IP",
"ClientIdHeader": "X-ClientId",
"HttpStatusCode": 429,
"GeneralRules": [
{
"Endpoint": "*",
"Period": "1m",
"Limit": 100
}
]
}
} Bind the configuration in Program.cs and switch the in‑memory store for the Redis implementation.
builder.Services.Configure<IpRateLimitOptions>(builder.Configuration.GetSection("IpRateLimiting"));
builder.Services.Configure<IpRateLimitPolicies>(builder.Configuration.GetSection("IpRateLimitPolicies"));
builder.Services.AddMemoryCache(); // required by the library
builder.Services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
builder.Services.AddSingleton<IProcessingStrategy, AsyncKeyLockProcessingStrategy>();
// Use Redis as the distributed counter store
builder.Services.AddSingleton<IRateLimitCounterStore, RedisRateLimitCounterStore>();
builder.Services.AddInMemoryRateLimiting(); // keeps rule parsing in memory
Applying the Middleware to Minimal APIs
Insert the middleware before any endpoint mapping so that each request is evaluated first.
var app = builder.Build();
app.UseIpRateLimiting();
app.MapGet("/weather", () => new[] { "Sunny", "Rainy", "Cloudy" });
app.MapGet("/status", () => Results.Ok(new { uptime = "24h", version = "1.0.0" }));
app.Run(); Testing the Limits Locally
Use curl in a loop to fire 120 requests against /weather. After the 100th request the server returns HTTP 429 with the default body “Too Many Requests”.
for i in $(seq 1 120); do curl -s -o /dev/null -w "%{http_code}\n" http://localhost:5000/weather; done The output shows a series of 200 codes followed by 429 codes, confirming that the distributed counter is shared across the process and, when scaled out, across all nodes.
Best Practices for Production
1. Set StackBlockedRequests to true if you want blocked attempts to count toward the quota, preventing burst attacks that alternate between allowed and blocked calls.
2. Use a dedicated Redis instance with persistence turned on; a volatile cache can lose counters after a restart, temporarily lifting limits.
3. Monitor the RateLimit-* keys in Redis; a high key churn may indicate a mis‑configured period or an abusive client.
4. Combine IP limits with client‑ID limits for APIs that require authentication, ensuring that a compromised key cannot flood the service.
Conclusion
By pairing AspNetCoreRateLimit with Redis, .NET 8 Minimal APIs gain a robust, horizontally scalable throttling layer. The approach requires only a few lines of configuration, yet it protects your services from overload, improves fairness, and provides clear metrics through Redis. Implement it early, tune the limits to your traffic profile, and let the distributed store keep your API responsive under any load.
Sources
- Microsoft Docs – ASP.NET Core Rate Limiting
- StackExchange.Redis Documentation
- AspNetCoreRateLimit GitHub Repository
Author: Mahmut Sarıkaya — sarikayadev.com