Skip to main content

Documentation 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] lets you annotate any controller action with a per-endpoint, per-identity rate limit that is enforced across all application instances via Redis. Unlike the built-in [EnableRateLimiting] attribute — which relies on in-process, in-memory counters — [RedisRateLimit] stores its counters in Redis, making limits consistent in multi-instance and container deployments. The attribute itself is pure metadata; enforcement is handled by RedisRateLimitingMiddleware, which reads the metadata on every incoming request.

The RedisRateLimitAttribute Class

The attribute is defined in Attributes/RedisRateLimitAttribute.cs:
namespace Dotnet_RateLimiter.Attributes;

public class RedisRateLimitAttribute : Attribute
{
    public int MaxRequests { get; }
    public int WindowSeconds { get; }
    
    public RedisRateLimitAttribute(int maxRequests, int windowSeconds)
    {
        MaxRequests = maxRequests;
        WindowSeconds = windowSeconds;
    }
}
The constructor takes two positional arguments that define the rate limit window. Both values are read-only once the attribute is constructed.

Parameters

maxRequests
int
required
Maximum number of requests allowed within the time window defined by windowSeconds. Once this count is exceeded for a given identity + endpoint combination, the middleware returns 429 Too Many Requests until the window resets. For example, maxRequests: 2 allows exactly 2 requests per window.
windowSeconds
int
required
Duration of the rate limit window in seconds. The Redis key holding the request counter is set to expire after this many seconds. For example, windowSeconds: 10 creates a 10-second sliding counter. This value is also written directly into the Retry-After response header so clients know when to retry.

Basic Usage

Apply the attribute directly to any controller action. The example below limits callers to 2 requests per 10 seconds on the GET /test/limited endpoint:
using Dotnet_RateLimiter.Attributes;
using Microsoft.AspNetCore.Mvc;

[ApiController, Route("[controller]")]
public class TestController : ControllerBase
{
    [HttpGet("limited")]
    [RedisRateLimit(maxRequests: 2, windowSeconds: 10)]
    public IActionResult GetLimited() => Ok("This is a limited endpoint!");

    [HttpGet("unlimited")]
    public IActionResult GetUnlimited() => Ok("This is unlimited! Sky is the limit.");
}
Endpoints without the attribute are completely ignored by RedisRateLimitingMiddleware — no Redis calls are made for them.

Multiple Endpoints with Different Limits

Each action can carry its own independent limit. The counters are keyed by {userType}:{identityKey}:{path}, so limits never bleed across endpoints:
using Dotnet_RateLimiter.Attributes;
using Microsoft.AspNetCore.Mvc;

[ApiController, Route("[controller]")]
public class ProductsController : ControllerBase
{
    // Generous limit for a read-heavy endpoint
    [HttpGet("search")]
    [RedisRateLimit(maxRequests: 50, windowSeconds: 60)]
    public IActionResult Search([FromQuery] string q) => Ok($"Results for: {q}");

    // Strict limit for a write endpoint
    [HttpPost("create")]
    [RedisRateLimit(maxRequests: 5, windowSeconds: 60)]
    public IActionResult Create([FromBody] object payload) => Ok("Created.");

    // Very tight limit for a sensitive endpoint
    [HttpPost("export")]
    [RedisRateLimit(maxRequests: 2, windowSeconds: 300)]
    public IActionResult Export() => Ok("Export started.");
}

The 429 Too Many Requests Response

When the rate limit is exceeded, RedisRateLimitingMiddleware short-circuits the pipeline and returns the following response — no controller code runs:
PropertyValue
HTTP status code429 Too Many Requests
Retry-After headerSet to windowSeconds (e.g., "10" for a 10-second window)
Response body (authenticated user)Dear user, you've reached your limit. Take a breath!
Response body (anonymous / guest)Guest limit reached. Please sign up for more quota!
The middleware determines the caller’s identity as follows:
  • Authenticated — uses ClaimTypes.NameIdentifier from context.User, falling back to context.User.Identity.Name or "authenticated_unknown". The Redis key prefix is user:.
  • Anonymous — uses context.Connection.RemoteIpAddress (falls back to "unknown"). The Redis key prefix is guest:.
The full Redis key written for each request is rate_limit:{userType}:{identityKey}:{path}, for example:
rate_limit:user:abc-123:/test/limited
rate_limit:guest:192.168.1.10:/test/limited

How the Middleware Reads the Attribute

RedisRateLimitingMiddleware is not an ASP.NET Core filter. It runs as standard middleware and inspects endpoint metadata directly:
var endpoint = context.GetEndpoint();
var rateLimitAttr = endpoint?.Metadata.GetMetadata<RedisRateLimitAttribute>();
If the endpoint has no RedisRateLimitAttribute in its metadata, the middleware calls _next(context) immediately and exits without touching Redis.
Because the middleware relies on context.GetEndpoint() to resolve the attribute, MapControllers() must be called during application setup — UseMiddleware<RedisRateLimitingMiddleware>() depends on the endpoint routing system having already matched the request to a controller action.

[RedisRateLimit] vs [EnableRateLimiting]

Both attributes are present in this project — choose the right one for your scenario:
Feature[RedisRateLimit][EnableRateLimiting("PolicyName")]
StorageRedis (distributed)In-process memory
Multi-instance safe✅ Yes❌ No — each instance has its own counter
Identity-aware✅ Per-user or per-IP, per-endpoint❌ Global per policy
ConfigurationInline on the attribute (maxRequests, windowSeconds)Defined once in AddCustomRateLimiter (window, permit limit, queue limit)
EnforcementRedisRateLimitingMiddleware (custom)UseRateLimiter() (built-in ASP.NET Core)
Available policiesFixed window via atomic LuaFixedWindowPolicy, SlidingWindowPolicy, ConcurrencyPolicy, BucketPolicy
Example[RedisRateLimit(maxRequests: 2, windowSeconds: 10)][EnableRateLimiting("FixedWindowPolicy")]
Use [RedisRateLimit] when you need per-identity enforcement that survives pod restarts or scales horizontally. Use [EnableRateLimiting] for lightweight, single-instance throttling or concurrency control.

Build docs developers (and LLMs) love