Rate Limiting in C# (.NET): System.Threading.RateLimiting Library
Rate limiting is a critical mechanism for protecting APIs, microservices, and web applications from overloads, DDoS attacks, and uncontrolled resource consumption. In the .NET ecosystem, starting with .NET 7, the built-in System.Threading.RateLimiting library provides flexible and high-performance tools for implementing various rate limiting strategies.
What is Rate Limiting and Why is it Needed?
Rate limiting allows you to control the number of operations (requests, method calls, transactions) within a specific time period. Main use cases:
- Protecting public APIs — preventing abuse by clients.
- Backend stabilization — evenly distributing load on databases and external services.
- Resource savings — limiting calls to paid third-party APIs.
- Ensuring SLA — guaranteeing equal access for all users.
Core Components of the System.Threading.RateLimiting Library
The library is built around the abstract class RateLimiter and several ready-made implementations:
1. TokenBucketRateLimiter
A classic algorithm that accumulates tokens at a specified rate (replenishment rate) and allows their use as needed. Suitable for smoothing out traffic spikes.
using System.Threading.RateLimiting;
var limiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions{ TokenLimit = 100, // Maximum number of tokens TokensPerPeriod = 20, // How many tokens are added per period ReplenishmentPeriod = TimeSpan.FromSeconds(1), // Replenishment period QueueLimit = 10, // Maximum queue size QueueProcessingOrder = QueueProcessingOrder.OldestFirst});
// Usage exampleusing var lease = await limiter.AcquireAsync(cancellationToken: CancellationToken.None);if (lease.IsAcquired){ // Perform operation Console.WriteLine("Token acquired");}else{ // Handle rejection Console.WriteLine("Limit exceeded, try again later");}2. ConcurrencyLimiter
Limits the number of concurrent operations. Ideal for controlling access to limited resources (connection pools, file descriptors).
var concurrencyLimiter = new ConcurrencyLimiter(new ConcurrencyLimiterOptions{ PermitLimit = 10, // Maximum 10 concurrent requests QueueLimit = 5, // Queue up to 5 requests QueueProcessingOrder = QueueProcessingOrder.NewestFirst});
// Usage in async contextasync Task ProcessRequestAsync(){ using var lease = await concurrencyLimiter.AcquireAsync(); if (lease.IsAcquired) { // Perform resource-intensive task await Task.Delay(1000); }}3. FixedWindowRateLimiter
The simplest algorithm: allows N operations within a fixed time interval (e.g., 100 requests per minute). After the window ends, the counter resets.
var fixedWindow = new FixedWindowRateLimiter(new FixedWindowRateLimiterOptions{ PermitLimit = 60, // 60 requests Window = TimeSpan.FromMinutes(1), // per 1 minute QueueLimit = 0, // No queue AutoReplenishment = true // Automatic window reset});
// Check limitRateLimitLease lease = fixedWindow.AttemptAcquire();if (lease.IsAcquired){ Console.WriteLine($"Remaining attempts: {lease.GetAllMetadata()}");}4. SlidingWindowRateLimiter
Mo
Also in library
Working with Dates in Kotlin: Libraries and Tools (Kotlinx-datetime, Joda-Time, java.time)
PDF Generation in Rust: Library Overview and Code Examples
Task Queues in TypeScript: Library Overview and Implementation
gomock for Go: Complete Guide with Examples