Back to Home

Rate limiting ASP.NET Core: setup and algorithms

Guide to setting up rate limiting in ASP.NET Core. Describes algorithms (Fixed Window, Token Bucket), policies, queues and rejection handling. Code examples for project integration.

Rate Limiting in ASP.NET Core: algorithms and policies
Advertisement 728x90

Setting Up Rate Limiting in ASP.NET Core: A Step-by-Step Guide for Developers

The rate limiting feature in ASP.NET Core lets you control server load, protect against DoS attacks, and ensure fair resource distribution. Setup requires two steps: registering services and adding middleware to the pipeline. All dependencies are included in the SDK—no extra packages needed.

In Program.cs, call AddRateLimiter on WebApplicationBuilder.Services:

builder.Services.AddRateLimiter(options =>
{
    // Konfiguratsiya politik
});

Then add the middleware:

Google AdInline article slot
app.UseRateLimiter();

This is the basic integration. Next up: details on algorithms and policies.

Algorithms and Selective Limiting

ASP.NET Core supports several rate limiting algorithms:

  • Fixed Window — fixed time window, simple but prone to load spikes.
  • Sliding Window — sliding window, distributes limits more evenly.
  • Token Bucket — token bucket, allows burst traffic.
  • Concurrency Limiter — limits concurrent requests.

Selectivity determines which requests to limit. The global limiter applies to all requests, while selective ones use keys (IP, user ID).

Google AdInline article slot

Example of a global limiter (100 requests per minute):

options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(
    httpContext => RateLimitPartition.GetFixedWindowLimiter(
        partitionKey: httpContext.Request.Headers.Host.ToString(),
        factory: partition => new FixedWindowRateLimiterOptions
        {
            AutoReplenishment = true,
            PermitLimit = 100,
            Window = TimeSpan.FromMinutes(1)
        }));
);

Grouping and Combining Limiters

Grouping by key is the foundation of selectivity. Use AddFixedWindowLimiter or custom policies.

Key grouping scenarios:

Google AdInline article slot
  • By IP: partitionKey: httpContext.Connection.RemoteIpAddress?.ToString()
  • By client: partitionKey: httpContext.User.Identity?.Name
  • By API endpoint: partitionKey: httpContext.Request.Path
  • Combined key: IP + User-Agent

Combining selective limiters via AddPolicy:

options.AddPolicy("ip", httpContext =>
{
    var ip = httpContext.Connection.RemoteIpAddress;
    return new FixedWindowRateLimiterOptions
    {
        PermitLimit = 50,
        Window = TimeSpan.FromMinutes(1),
        QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
        QueueLimit = 10
    };
});

New feature: combining non-selective limiters—multiple global limiters with queues.

Queues and Rejection Handling

Enable queues to smooth out spikes:

  • QueueLimit — maximum in queue.
  • QueueProcessingOrder — order (OldestFirst / NewestFirst).

Rejection actions can be set globally or per policy:

options.OnRejected = (context, token) =>
{
    context.HttpContext.Response.StatusCode = 429;
    context.HttpContext.Response.ContentType = "application/json";
    return context.HttpContext.Response.WriteAsync(
        "{"too many requests. try again later.", token);
};

Named and Anonymous Policies

Named policies are applied via attributes to controllers/actions:

[EnableRateLimiting("policy1")]
public class ApiController : ControllerBase { }

Simple registration:

options.AddPolicy("policy1", httpContext =>
    new TokenBucketRateLimiterOptions
    {
        TokenLimit = 100,
        QueueLimit = 20,
        ReplenishmentPeriod = TimeSpan.FromMinutes(1),
        TokensPerPeriod = 100,
        AutoReplenishment = true
    });

Anonymous policies — a bonus not covered in MS documentation. Implemented via IRateLimiter directly in selectors.

Example:

options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext>(
    context => new CustomRateLimiter(context));

public class CustomRateLimiter : FixedWindowRateLimiter
{
    // Kastomnaya logic
}

Linking to routes: [EnableRateLimiting("api")] or disable with [DisableRateLimiting].

Key Points

  • Rate limiting operates at the middleware level, before controllers.
  • Always configure OnRejected for 429 Too Many Requests.
  • Use queues for high-load scenarios.
  • Combine policies for granular control (IP + endpoint).
  • Anonymous policies extend capabilities beyond the standard API.

— Editorial Team

Advertisement 728x90

Read Next