Rate Limiting In .NET 7.0

Rate limiting in .NET is a technique used to control the rate at which requests are made to a specific endpoint or service. It is typically used to prevent the overuse of resources or to implement a pay-per-use pricing model. Rate limiting can be implemented in various ways, such as using built-in libraries in the .NET framework or using third-party libraries and services.

I have posted an article on implementing Rate Limiting in .NET 6.0. I have listed down the purpose of Rate Limiting in this article.

In .NET 7.0, the rate limiting feature is implemented using System.Net.Http.RateLimiting library. This library allows developers to configure rate limits for specific endpoints and to handle requests that exceed the rate limit. The library provides a RateLimiter class that can be used to create and configure rate limit rules, and a RateLimitedHttpClient class that can be used to add rate limiting behavior to an HttpClient instance.

There are multiple combinations of rate limiting algorithms to handle the flow of requests. Microsoft has decided to present the below four algorithms in .NET 7.0.

Concurrency Limit

Concurrency limiter limits how many concurrent requests can access a resource. If your limit is 50, then 50 requests can access a resource at once and the 51st request will not be processed. Once the request is completed, the number of allowed requests increased to 1, when the second request is complete, the number increased to 2 and this will continue till the count reaches 50.

Token Bucket Limit

This algorithm limits the number of requests based on a defined amount of allowed requests. For an instance, assume that we have an application with an imaginary bucket. This bucket can hold 10 tokens and every two minutes 2 tokens are added to this bucket. If a user makes a request, it takes a token so we are left with 9. 3 more request comes in and each takes a token and leaving us with 6 tokens. After two minutes have passed, we get 2 new tokens. Now the bucket has 8 tokens. 8 requests come in and take the remaining tokens and leaving the bucket with 0 tokens. If another comes, it is not allowed to access the resource until the bucket fills with tokens.

Fixed Window Limit

The fixed window algorithm uses the concept of a window with an amount of time. The request limit will be applied within this window before we move to the next window. In this algorithm, when we move to the next window, the request limit will be reset back to the starting point. Assume that we have a window of 3 seconds and a request limit of 10. If the application receives 11 requests within 3 seconds, 10 requests will have access to the resource and the 11th request will be rejected. Once the 3 seconds have passed, the window and the request limit will be reset.

Sliding Window Limit

The sliding window algorithm is like the fixed window algorithm but with an addition of segments. A segment is nothing but it is a part of the window. Assume that we have a window of 2 hours and split it into 4 thirty minutes segments. There is a current segment index that will be pointing to the newest segment in the window. The incoming request will be going to the current segment. Every thirty minutes, the window slides by one segment. If there were any requests in the past window segment, these are now refreshed and the request limit gets increased by the requests count from the past segment.

I would request you to look at the Microsoft blog by Brennen Conroy. It has a detailed explanation of the sliding window algorithm.

Let us look at simple service.

The tools which I have used for this tutorial are.

  1. VS 2022 Community Edition
  2. .NET 7.0
  3. Swagger

For this tutorial, I will be using the Web API Weather template.

The source code can be downloaded from GitHub

The project structure looks like below.

Rate Limiting in .NET 7.0

Fixed Window

Let us make the below changes.

Include the library System.Threading.RateLimiting in Program.cs

using System.Threading.RateLimiting;

Then add the below lines of code to include the Fixed Window limiter.

//Window Rate Limiter
builder.Services.AddRateLimiter(options => {
    options.AddFixedWindowLimiter("Fixed", opt => {
        opt.Window = TimeSpan.FromSeconds(3);
        opt.PermitLimit = 3;
        //opt.QueueLimit = 2;
        //opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
    });
});

Add the below line of code as well in Program.cs

app.UseRateLimiter();

The entire code from Program.cs below

using Microsoft.AspNetCore.RateLimiting;
using System.Threading.RateLimiting;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//Window Rate Limiter
builder.Services.AddRateLimiter(options => {
    options.AddFixedWindowLimiter("Fixed", opt => {
        opt.Window = TimeSpan.FromSeconds(3);
        opt.PermitLimit = 3;
        //opt.QueueLimit = 2;
        //opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
    });
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) {
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.UseAuthorization();
app.MapControllers();
app.UseRateLimiter();
app.Run();

Now add the below decorator at the WeatherForecastController.cs class- class level

[EnableRateLimiting("Fixed")]

The entire code from WeatherForecastController.cs as below

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.RateLimiting;
namespace WeatherService.Controllers {
    [ApiController]
    [Route("api/[controller]")]
    [EnableRateLimiting("Fixed")]
    public class WeatherForecastController: ControllerBase {
        private static readonly string[] Summaries = new [] {
            "Freezing",
            "Bracing",
            "Chilly",
            "Cool",
            "Mild",
            "Warm",
            "Balmy",
            "Hot",
            "Sweltering",
            "Scorching"
        };
        private readonly ILogger < WeatherForecastController > _logger;
        public WeatherForecastController(ILogger < WeatherForecastController > logger) {
                _logger = logger;
            }
            [HttpGet(Name = "GetWeatherForecast")]
        public IEnumerable < WeatherForecast > Get() {
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast {
                Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
                    TemperatureC = Random.Shared.Next(-20, 55),
                    Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            }).ToArray();
        }
    }
}

As per the configuration, within 3 seconds, we can raise 3 requests.

Let us test the endpoint.

Please execute the endpoint consecutively four times, three requests would access the resource, when we raise the fourth request, it will be rejected

Rate Limiting in .NET 7.0

Sliding Window

 The below needs to be added to Program.cs

//Sliding Window Rate Limiter
options.AddSlidingWindowLimiter("Sliding", opt => {
    opt.Window = TimeSpan.FromSeconds(10);
    opt.PermitLimit = 4;
    opt.QueueLimit = 2;
    opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
    opt.SegmentsPerWindow = 2;
});

Token Bucket

The below code goes into Program.cs

//Token Bucket Rate Limiter
options.AddTokenBucketLimiter("Token", opt => {
    opt.TokenLimit = 4;
    opt.QueueLimit = 2;
    opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
    opt.ReplenishmentPeriod = TimeSpan.FromSeconds(10);
    opt.TokensPerPeriod = 4;
    opt.AutoReplenishment = true;
});

Concurrency Limiter

This algorithm is used to control the async requests. The below code changes will be added to Program.cs

//Concurrency Limiter
options.AddConcurrencyLimiter("Concurrency", opt => {
    opt.PermitLimit = 10;
    opt.QueueLimit = 2;
    opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
});

I have explained the four Rate Limiter algorithms introduced in .NET 7.0. I have tested the Fixed Window Algorithm. I leave the rest of the three algorithms to you to validate and provide your comments in the comment box below.