Skip to content

Rate Limiting

SimpleModule wires ASP.NET Core's built-in rate limiter into the request pipeline and lets you author policies in two places: in code, for endpoints whose limits are part of the framework contract, and in the database, for limits an administrator should tune at runtime without redeploying.

Applying a policy to an endpoint

Use the RateLimit(policyName) extension on any endpoint convention builder:

csharp
using SimpleModule.Core.RateLimiting;

public sealed class CreateEndpoint : IEndpoint
{
    public void Map(IEndpointRouteBuilder app) =>
        app.MapPost("/products", Handle)
           .RateLimit(RateLimitPolicies.FixedDefault);
}

The constants in RateLimitPolicies are the canonical names of the policies the framework ships with, so a rename can never silently miss a call site:

ConstantWire nameNotes
FixedDefaultfixed-defaultSensible default for most read/write endpoints.
SlidingStrictsliding-strictTighter sliding window for hot paths.
TokenBuckettoken-bucketBursty workloads (file uploads, batch ingestion).
AuthStrictauth-strictApplied to OpenIddict login/refresh endpoints by default.

DB-defined rules

Each shipped policy is backed by a row in the RateLimiting_Rules table. An administrator can change the limit, window, or target without a deploy — RateLimitRuleCache reloads the live rules and rebuilds the runtime partitioner.

A rule has these knobs (modules/RateLimiting/src/SimpleModule.RateLimiting.Contracts/RateLimitRule.cs):

FieldTypeDescription
PolicyNamestringThe wire name applied via .RateLimit("...").
PolicyTypeFixedWindow | SlidingWindow | TokenBucketAlgorithm.
TargetIp | User | IpAndUser | GlobalWhat to partition on.
PermitLimitintRequests allowed per window (fixed/sliding).
WindowSecondsintWindow length in seconds.
SegmentsPerWindowintSliding-window resolution.
TokenLimitintBucket size (token bucket).
TokensPerPeriodintRefill rate (token bucket).
ReplenishmentPeriodSecondsintRefill period (token bucket).
QueueLimitintRequests parked when capacity is exhausted.
EndpointPatternstring?Optional route pattern to narrow the rule to a subset of endpoints.
IsEnabledboolToggle without deleting.

Admin UI

The RateLimiting module mounts an admin view at /rate-limiting/manage and exposes the policy CRUD over /api/rate-limiting/. The endpoints are protected by RateLimiting.View, RateLimiting.Create, RateLimiting.Update, and RateLimiting.Delete permissions; the active-policies preview at /api/rate-limiting/active is read-only.

Querying from other modules

If a module needs to read or mutate rules programmatically, depend on the contract:

csharp
public interface IRateLimitingContracts
{
    Task<IEnumerable<RateLimitRule>> GetAllRulesAsync();
    Task<RateLimitRule?> GetRuleByIdAsync(RateLimitRuleId id);
    Task<RateLimitRule> CreateRuleAsync(CreateRateLimitRuleRequest request);
    Task<RateLimitRule> UpdateRuleAsync(RateLimitRuleId id, UpdateRateLimitRuleRequest request);
    Task DeleteRuleAsync(RateLimitRuleId id);
}

Response headers

When a policy rejects a request the framework returns 429 Too Many Requests. The RateLimitHeaderMiddleware adds standard Retry-After and the remaining-budget headers based on the configured policy so well-behaved clients can back off without guessing.

Next Steps

  • Configuration — built-in policy defaults and storage tuning.
  • Endpoints — the .RateLimit(...) extension in context.

Released under the MIT License.