Web API  

Rate Limiting in ASP.NET Core: Protecting APIs from Abuse and Traffic Spikes

Public APIs are constantly exposed to unpredictable traffic. A sudden spike in legitimate requests, an aggressive web crawler, or a malicious bot can overwhelm application resources and degrade performance for every user. Without proper request throttling, APIs may experience increased latency, excessive infrastructure costs, or even complete service outages.

ASP.NET Core includes a built-in Rate Limiting middleware that allows developers to control how many requests clients can make over a specific period. By applying appropriate rate limiting policies, applications can protect backend services, improve fairness among users, and maintain consistent performance under heavy load.

Rather than relying solely on external API gateways, this article explains how to implement production-ready rate limiting directly in ASP.NET Core.

Note: Rate limiting is not a replacement for authentication, authorization, or DDoS protection. It is one layer of a broader API security strategy.

Why Rate Limiting Matters

Without rate limiting, applications may encounter:

  • API abuse

  • Bot traffic

  • Denial-of-service attempts

  • Database overload

  • Excessive cloud costs

  • Poor user experience during traffic spikes

Limiting request rates helps maintain predictable application performance.

Common Rate Limiting Algorithms

ASP.NET Core supports several algorithms.

AlgorithmBest For
Fixed WindowSimple APIs
Sliding WindowPublic APIs
Token BucketBurst traffic
Concurrency LimiterLong-running requests

Each algorithm balances fairness, performance, and implementation complexity differently.

Rate Limiting Architecture

flowchart LR

A[Client]
B[Rate Limiter]
C{Limit Exceeded?}
D[ASP.NET Core API]
E[(Database)]

A --> B
B --> C

C -->|No| D
D --> E

C -->|Yes| F[HTTP 429 Too Many Requests]

Every incoming request passes through the rate limiter before reaching the application.

Installing the Middleware

Register rate limiting during application startup.

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

Enable the middleware.

var app = builder.Build();

app.UseRateLimiter();

app.MapControllers();

app.Run();

The middleware processes requests before controller actions execute.

Configuring a Fixed Window Policy

A fixed window policy allows a specific number of requests during a defined time period.

builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter(
        "fixed",
        limiterOptions =>
        {
            limiterOptions.PermitLimit = 100;

            limiterOptions.Window =
                TimeSpan.FromMinutes(1);

            limiterOptions.QueueLimit = 0;
        });
});

This policy permits up to 100 requests per minute.

Applying a Rate Limit

Apply the policy to an endpoint.

app.MapGet("/products", GetProducts)
    .RequireRateLimiting("fixed");

Only requests to this endpoint are subject to the configured policy.

Using a Sliding Window

Sliding windows distribute requests more evenly.

builder.Services.AddRateLimiter(options =>
{
    options.AddSlidingWindowLimiter(
        "sliding",
        limiterOptions =>
        {
            limiterOptions.PermitLimit = 100;

            limiterOptions.Window =
                TimeSpan.FromMinutes(1);

            limiterOptions.SegmentsPerWindow = 6;
        });
});

This approach reduces sudden bursts at window boundaries.

Using a Token Bucket

Token Bucket is ideal for bursty traffic.

builder.Services.AddRateLimiter(options =>
{
    options.AddTokenBucketLimiter(
        "token",
        limiterOptions =>
        {
            limiterOptions.TokenLimit = 200;

            limiterOptions.TokensPerPeriod = 20;

            limiterOptions.ReplenishmentPeriod =
                TimeSpan.FromSeconds(10);
        });
});

Clients can consume available tokens quickly, while new tokens are replenished over time.

Request Processing Flow

sequenceDiagram

participant Client
participant RateLimiter
participant API

Client->>RateLimiter: HTTP Request

alt Limit Available
    RateLimiter->>API: Forward Request
    API-->>Client: HTTP 200
else Limit Exceeded
    RateLimiter-->>Client: HTTP 429
end

Requests exceeding the configured policy receive an HTTP 429 response.

Choosing the Right Algorithm

ScenarioRecommended Algorithm
Internal APIsFixed Window
Public REST APIsSliding Window
AI APIsToken Bucket
File Upload APIsConcurrency Limiter
Authentication EndpointsSliding Window

Choose the algorithm based on expected traffic patterns rather than using one policy everywhere.

Customizing Rejected Requests

Provide a meaningful response when requests exceed the limit.

builder.Services.AddRateLimiter(options =>
{
    options.OnRejected = async (
        context,
        cancellationToken) =>
    {
        context.HttpContext.Response.StatusCode = 429;

        await context.HttpContext.Response.WriteAsync(
            "Too many requests.",
            cancellationToken);
    };
});

Clear error messages help API consumers understand why requests were rejected.

Common Production Mistakes

ProblemRoot Cause
Legitimate users blockedLimits configured too aggressively
APIs still overloadedLimits too permissive
Authentication endpoint abuseNo rate limiting applied
Inconsistent throttlingDifferent policies without planning
Poor user experienceNo retry guidance after HTTP 429
Memory pressureExcessive request queueing

Effective rate limiting requires balancing protection with usability.

Best Practices

  • Apply different policies for different endpoints.

  • Use stricter limits for authentication endpoints.

  • Return HTTP 429 for rejected requests.

  • Include retry guidance where appropriate.

  • Monitor rejected request metrics.

  • Combine rate limiting with authentication.

  • Test policies under realistic production traffic.

Common Anti-Patterns

Avoid these common mistakes:

  • Applying identical limits to every endpoint.

  • Ignoring authenticated versus anonymous users.

  • Using unlimited request queues.

  • Treating rate limiting as DDoS protection.

  • Configuring limits without monitoring results.

  • Forgetting to document API rate limits.

FAQ

Which rate limiting algorithm should I use?

For most public APIs, the Sliding Window algorithm provides a good balance between fairness and predictable request distribution. Token Bucket is better when occasional bursts are expected.

What happens when a client exceeds the limit?

ASP.NET Core returns an HTTP 429 (Too Many Requests) response, indicating that the client has exceeded the configured request limit.

Can different endpoints use different policies?

Yes. Each endpoint can have its own rate limiting policy based on its expected workload and security requirements.

Does rate limiting work with Minimal APIs?

Yes. The built-in Rate Limiting middleware supports Minimal APIs, MVC controllers, Razor Pages, and endpoint routing.

Conclusion

Rate limiting is an essential safeguard for modern ASP.NET Core APIs. By controlling request volume, applications can prevent abuse, protect backend resources, and maintain consistent performance during periods of heavy traffic.

ASP.NET Core's built-in Rate Limiting middleware provides flexible algorithms such as Fixed Window, Sliding Window, Token Bucket, and Concurrency Limiter, making it easy to tailor request throttling for different workloads. Combined with authentication, monitoring, and API gateways, rate limiting helps build secure, scalable, and resilient applications ready for production environments.