Rate Limiting in an ASP.NET Core Web API with AspNetCoreRateLimit Library

Rate Limiting in an ASP.NET Core Web API with AspNetCoreRateLimit Library

·

3 min read

Everything has finite resources, Services and Apis need to protect themselves from excessive use to maintain service availability. Even highly scalability systems should have limits on consumption at some level.

Rate Limiting is the answer and is a way for developers to control the number of allowed requests for a resource within a specific time window.

When too many users are accessing the API, a rate limit can be very useful.

In this article, I will show you how to implement Basic Rate Limiting in an ASP.NET Core Web API with the AspNetCoreRateLimit library

Also, .NET Announced built-in Rate Limiting support as part of .NET 7. (My next Article will be about implementing Rate limiting with .NET 7 built-in part)

It is possible to implement your Rate Limiter by adding middleware but there is already a nice library called AspNetCoreRateLimit.

You can access the GitHub page via the link below.
GitHub: https://github.com/stefanprodan/AspNetCoreRateLimit

Let's Create a Web API project.
I am going to add it using dotnet tool. Also, you can create it in visual studio

dotnet new webapi -o AspNetCoreRateLimitExample

You can access the repository on GitHub...

I will show it on the default created controller (WeatherForecastController)

using Microsoft.AspNetCore.Mvc;

namespace AspNetCoreRateLimitExample.Controllers;

[ApiController]
[Route("[controller]")]
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();
    }
}

When we run it we will get this endpoint and response pictures below.

Now let's add the NuGet package from Package Manager Console

Install-Package AspNetCoreRateLimit

For basic usage, there are 2 places to edit.
Program.cs and appsettings.json

Program.cs

using AspNetCoreRateLimit;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddOptions();
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// in-memory cache is using to store rate limit counters
builder.Services.AddMemoryCache();

// load configuration from appsettings.json
builder.Services.Configure<IpRateLimitOptions>(builder.Configuration.GetSection("IpRateLimiting"));

// inject counter and rules stores
builder.Services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
builder.Services.AddInMemoryRateLimiting();

// the clientId/clientIp resolvers use IHttpContextAccessor.
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

// AspNetCoreRateLimit configuration

var app = builder.Build();

// enable AspNetCoreRateLimit Middleware
app.UseIpRateLimiting();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseRouting();

app.UseAuthorization();

app.MapControllers();

app.Run();

appsettings.json

{
    "Logging": {
        "LogLevel": {
            "Default": "Information",
            "Microsoft.AspNetCore": "Warning"
        }
    },
    "AllowedHosts": "*",
    "IpRateLimiting": {
        "EnableEndpointRateLimiting": false,
        "StackBlockedRequests": false,
        "RealIpHeader": "X-Real-IP",
        "HttpStatusCode": 429,
        "GeneralRules": [
            {
                "Endpoint": "*",
                "Period": "1m",
                "Limit": 2
            }
        ]
    }
}

Output

Also, you can add configuration for specific endpoints by changing "EnableEndpointRateLimiting": false to "EnableEndpointRateLimiting": true

"IpRateLimiting": {
        "EnableEndpointRateLimiting": true,
        "StackBlockedRequests": false,
        "RealIpHeader": "X-Real-IP",
        "HttpStatusCode": 429,
        "GeneralRules": [
            {
                "Endpoint": "get:/SomeEndPoint/*",
                "Period": "10s",
                "Limit": 5
            },
            {
                "Endpoint": "*",
                "Period": "1s",
                "Limit": 20
            }
        ]
    },

You can find more details about this middleware and NuGet package and other configuration options in the GitHub repository. You can find the source code here