By the end of this guide you will have a running ASP.NET Core 10 API with cluster-wide, atomic Redis rate limiting protecting your endpoints. You’ll register the services, configure the Redis connection, apply theDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/nimanikoo/Dotnet-RateLimiter/llms.txt
Use this file to discover all available pages before exploring further.
[RedisRateLimit] attribute to a controller action, and observe the HTTP 429 response — all in under five minutes.
Prerequisites
Before you begin, make sure you have the following available:- .NET 10 SDK — Download here
- A Redis instance — local (
localhost:6379) or via Docker (see the tip below) - NuGet access — to restore the packages listed in the next step
Steps
Add NuGet packages
The project depends on the following NuGet packages. Add them to your Or reference them directly in your project file:
.csproj or install via the CLI:Configure appsettings.json
Add the
Redis section to your appsettings.json. The ConnectionString key is read by AddCustomRateLimiter to connect to Redis via StackExchange.Redis:The
abortConnect=false option tells StackExchange.Redis not to throw an exception on startup if Redis is temporarily unavailable. This is important in containerized environments where the API may start before Redis is fully ready.Register services and configure the middleware pipeline
Wire up the rate limiter, Redis connection, health checks, and Swagger in
Program.cs using the AddCustomRateLimiter extension method. Then configure the full middleware pipeline:AddCustomRateLimiter internally:- Connects to Redis using
configuration.GetSection("Redis:ConnectionString"), falling back to"localhost:6379"if the key is absent. - Registers
IConnectionMultiplexerandRedisRateLimiteras singletons. - Adds a Redis health check tagged
["db", "cache", "redis"]. - Configures the Health Checks UI to poll
http://localhost:8080/healthevery 5 seconds with in-memory storage. - Registers all four in-process limiter policies, each with a rejection status code of 429.
Protect an endpoint with [RedisRateLimit]
Decorate any controller action with The The middleware reads this attribute from the endpoint metadata on every request and passes
[RedisRateLimit(maxRequests, windowSeconds)] to enable distributed, atomic Redis rate limiting on that endpoint. Here is the real example from TestController.cs:RedisRateLimitAttribute stores the MaxRequests and WindowSeconds values:MaxRequests and WindowSeconds directly into the Lua script execution.HTTP 429 Response Behavior
When the Lua script returns0 (limit exceeded), the RedisRateLimitingMiddleware sets the response status to 429 Too Many Requests and writes a Retry-After header containing the window duration in seconds. The response body is a human-readable message that varies based on the resolved client identity:
| Client Type | Response Message |
|---|---|
| Authenticated user | Dear user, you've reached your limit. Take a breath! |
| Anonymous guest | Guest limit reached. Please sign up for more quota! |
Retry-After header value is exactly the windowSeconds value from the attribute — for [RedisRateLimit(maxRequests: 2, windowSeconds: 10)], the header will be Retry-After: 10.
The
Retry-After header is set using context.Response.Headers.RetryAfter. Clients and API gateways that respect this standard header will automatically back off and retry after the specified number of seconds.