All four built-in rate limiting algorithms in one place β Fixed Window, Sliding Window, Token Bucket, and Concurrency Limiter with real endpoints, integration tests, and HTTP 429 responses done right.
If this sample saved you time, consider joining our Patreon community. You'll get exclusive .NET tutorials, premium code samples, and early access to new content β all for the price of a coffee.
π Join CodingDroplets on Patreon
Prefer a one-time tip? Buy us a coffee β
- How to configure all four built-in rate limiting algorithms in ASP.NET Core
- How to apply policies per-controller or per-action with
[EnableRateLimiting] - How to exempt specific endpoints using
[DisableRateLimiting] - How to return structured HTTP 429 Too Many Requests responses with
Retry-Afterheaders - How to use the modern Scalar UI (OpenAPI) for interactive API exploration
- How to write integration tests that exercise rate-limited endpoints
Incoming HTTP Request
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ASP.NET Core Middleware Pipeline β
β ββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β app.UseRateLimiter() β FIRST β β
β β Checks policy for this endpoint β β
β β β β
β β βββββββββββββββββββββββββββββββββββββββββββ β β
β β β Within limit? β β β
β β β YES β forward to controller β β β
β β β NO β OnRejected β HTTP 429 β β β
β β βββββββββββββββββββββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β Controllers annotated with [EnableRateLimiting("x")]β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
βΌ βΌ
200 OK Response 429 Too Many Requests
+ Retry-After header
+ Problem Details JSON
| Algorithm | Policy Name | Config | Best For |
|---|---|---|---|
| Fixed Window | fixed |
5 req / 10 s | Simple API throttling |
| Sliding Window | sliding |
10 req / 20 s (4 segments) | Smooth burst control |
| Token Bucket | token |
8 tokens, refill 2 / 5 s | Burst + steady average |
| Concurrency | concurrency |
Max 3 concurrent | Protecting slow resources |
dotnet-rate-limiting-api/
βββ dotnet-rate-limiting-api.sln
βββ RateLimitingApi/
β βββ Controllers/
β β βββ FixedWindowController.cs β Fixed Window demo
β β βββ SlidingWindowController.cs β Sliding Window demo
β β βββ TokenBucketController.cs β Token Bucket demo
β β βββ ConcurrencyController.cs β Concurrency Limiter demo
β β βββ NoLimitController.cs β [DisableRateLimiting] demo
β βββ Models/
β β βββ ApiResponse.cs β Generic response envelope
β β βββ Product.cs β Sample domain model
β βββ Properties/
β β βββ launchSettings.json
β βββ Program.cs β All rate limiters registered here
βββ RateLimitingApi.Tests/
βββ RateLimitingIntegrationTests.cs β 16 integration tests
- .NET 10 SDK
- Any IDE: Visual Studio 2022+, VS Code, or JetBrains Rider
# Clone the repo
git clone https://github.com/codingdroplets/dotnet-rate-limiting-api.git
cd dotnet-rate-limiting-api
# Build
dotnet build -c Release
# Run the API
cd RateLimitingApi
dotnet run
# Open Scalar UI β http://localhost:5289/scalar/v1builder.Services.AddRateLimiter(options =>
{
// 1. Fixed Window β 5 requests per 10 seconds
options.AddFixedWindowLimiter(policyName: "fixed", opt =>
{
opt.PermitLimit = 5;
opt.Window = TimeSpan.FromSeconds(10);
opt.QueueLimit = 2;
});
// 2. Sliding Window β 10 requests per 20 seconds (4 segments)
options.AddSlidingWindowLimiter(policyName: "sliding", opt =>
{
opt.PermitLimit = 10;
opt.Window = TimeSpan.FromSeconds(20);
opt.SegmentsPerWindow = 4;
opt.QueueLimit = 2;
});
// 3. Token Bucket β 8 tokens, replenish 2 every 5 seconds
options.AddTokenBucketLimiter(policyName: "token", opt =>
{
opt.TokenLimit = 8;
opt.ReplenishmentPeriod = TimeSpan.FromSeconds(5);
opt.TokensPerPeriod = 2;
opt.AutoReplenishment = true;
opt.QueueLimit = 2;
});
// 4. Concurrency β max 3 simultaneous requests
options.AddConcurrencyLimiter(policyName: "concurrency", opt =>
{
opt.PermitLimit = 3;
opt.QueueLimit = 2;
});
// Custom 429 response with Retry-After header
options.OnRejected = async (context, ct) =>
{
context.HttpContext.Response.StatusCode = 429;
context.HttpContext.Response.Headers["Retry-After"] = "10";
await context.HttpContext.Response.WriteAsJsonAsync(new
{
status = 429,
error = "Too Many Requests",
message = "Rate limit exceeded. Please wait before retrying.",
retryAfterSeconds = 10
}, cancellationToken: ct);
};
});
// IMPORTANT: UseRateLimiter() must come before MapControllers()
app.UseRateLimiter();// Apply a named policy to all actions in this controller
[EnableRateLimiting("fixed")]
public class FixedWindowController : ControllerBase { ... }
// Exempt an endpoint from all rate limiting
[DisableRateLimiting]
public class NoLimitController : ControllerBase { ... }| Method | Endpoint | Description |
|---|---|---|
GET |
/api/nolimit/status |
API status & policy overview |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/fixedwindow/products |
List all products |
GET |
/api/fixedwindow/products/{id} |
Get product by ID |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/slidingwindow/orders |
List all orders |
GET |
/api/slidingwindow/orders/{id} |
Get order by ID |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/tokenbucket/reports |
List all reports |
GET |
/api/tokenbucket/reports/{id} |
Get report by ID |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/concurrency/inventory |
List inventory (simulated slow query) |
GET |
/api/concurrency/inventory/{id} |
Get inventory item by ID |
dotnet test -c Release16 integration tests cover all five controllers:
| Area | Coverage |
|---|---|
| Happy path | 200 OK for all controllers |
| Not found | 404 for all controllers |
| JSON content-type | Validated on all responses |
| Response envelope | success: true structure verified |
| Use Case | Best Algorithm |
|---|---|
| Simple API key / per-IP throttle | Fixed Window |
| Smooth traffic shaping, no boundary spikes | Sliding Window |
| Allow short bursts, enforce an average rate | Token Bucket |
| Protect expensive DB queries / third-party APIs | Concurrency |
Once running, open Scalar UI in your browser:
http://localhost:5289/scalar/v1
OpenAPI JSON spec:
http://localhost:5289/openapi/v1.json
- Rate limiting middleware in ASP.NET Core β Microsoft Learn
- System.Threading.RateLimiting β .NET API
This project is licensed under the MIT License.
| Platform | Link |
|---|---|
| π Website | https://codingdroplets.com/ |
| πΊ YouTube | https://www.youtube.com/@CodingDroplets |
| π Patreon | https://www.patreon.com/CodingDroplets |
| β Buy Me a Coffee | https://buymeacoffee.com/codingdroplets |
| π» GitHub | http://github.com/codingdroplets/ |
Want more samples like this? Support us on Patreon or buy us a coffee β β every bit helps keep the content coming!