Skip to content

Add Volo.Abp.OperationRateLimiting module#25024

Merged
hikalkan merged 15 commits into
devfrom
Operation-Rate-Limiting
Mar 8, 2026
Merged

Add Volo.Abp.OperationRateLimiting module#25024
hikalkan merged 15 commits into
devfrom
Operation-Rate-Limiting

Conversation

@maliming

@maliming maliming commented Mar 6, 2026

Copy link
Copy Markdown
Member

Document: https://github.com/abpframework/abp/blob/dev/docs/en/framework/infrastructure/operation-rate-limiting.md

Resolve #17815

Demo UI: #25025

Adds the Volo.Abp.OperationRateLimiting package — a web-agnostic, application-level rate limiting module for ABP Framework.

Unlike ASP.NET Core's built-in HTTP rate limiting middleware (which operates at the request pipeline level), this module is designed to be called explicitly from application service methods, domain logic, or anywhere in the DI container. It is not tied to HTTP and has no dependency on HttpContext.

Getting started

Add a dependency on AbpOperationRateLimitingModule and define policies in ConfigureServices:

[DependsOn(typeof(AbpOperationRateLimitingModule))]
public class MyModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        Configure<AbpOperationRateLimitingOptions>(options =>
        {
            options.AddPolicy("SendSmsCode", policy =>
            {
                policy.WithFixedWindow(TimeSpan.FromMinutes(1), maxCount: 3)
                      .PartitionByParameter();
            });
        });
    }
}

Then inject IOperationRateLimitingChecker and call CheckAsync in your application service. If the limit is exceeded it throws AbpOperationRateLimitingException (mapped to HTTP 429):

public class SmsAppService : ApplicationService
{
    private readonly IOperationRateLimitingChecker _checker;

    public SmsAppService(IOperationRateLimitingChecker checker)
    {
        _checker = checker;
    }

    public async Task SendCodeAsync(string phoneNumber)
    {
        await _checker.CheckAsync("SendSmsCode", phoneNumber);

        // proceed with sending SMS...
    }
}

Extension methods are provided for all four checker methods (CheckAsync, IsAllowedAsync, GetStatusAsync, ResetAsync) so you can pass a parameter string directly without constructing OperationRateLimitingContext manually.

Partition types

Method Partition key source
PartitionByParameter() context.Parameter (caller-provided)
PartitionByCurrentUser() ICurrentUser.Id (auto-resolved)
PartitionByCurrentTenant() ICurrentTenant.Id (auto-resolved)
PartitionByClientIp() IWebClientInfoProvider.ClientIpAddress (auto-resolved)
PartitionByEmail() context.ParameterICurrentUser.Email
PartitionByPhoneNumber() context.ParameterICurrentUser.PhoneNumber
PartitionBy(resolver) custom Func<OperationRateLimitingContext, Task<string>>

PartitionByCurrentUser, PartitionByCurrentTenant, and PartitionByClientIp resolve exclusively from their respective services and do not fall back to context.Parameter. This avoids partition key conflicts in composite policies where Parameter is shared across all rules. If you need to check rate limits for a specific user, tenant, or IP explicitly, use PartitionByParameter() instead:

// Admin checking another user's rate limit
await checker.CheckAsync("UserApiLimit",
    new OperationRateLimitingContext { Parameter = targetUserId.ToString() });

Composite rules

A policy can have multiple rules (AddRule()). All rules are checked in a two-phase flow: Phase 1 reads current counts without incrementing; Phase 2 increments only after all rules pass. This prevents wasted quota on requests that would be blocked by a later rule.

options.AddPolicy("LoginAttempt", policy =>
{
    // per-IP burst limit (short window)
    policy.AddRule(rule => rule
        .WithFixedWindow(TimeSpan.FromMinutes(1), maxCount: 10)
        .PartitionByClientIp());

    // per-user daily limit (long window)
    policy.AddRule(rule => rule
        .WithFixedWindow(TimeSpan.FromHours(24), maxCount: 50)
        .PartitionByCurrentUser());
});

Multi-tenancy

All partition types default to a global counter (shared across tenants). Call .WithMultiTenancy() on a rule to opt into per-tenant counter isolation:

// global — all tenants share the same counter
policy.WithFixedWindow(TimeSpan.FromHours(1), maxCount: 100)
      .PartitionByParameter();

// isolated — each tenant has its own counter for the same parameter
policy.WithFixedWindow(TimeSpan.FromHours(1), maxCount: 100)
      .WithMultiTenancy()
      .PartitionByParameter();

Client IP resolution

PartitionByClientIp() resolves the client IP address via the existing IWebClientInfoProvider abstraction from Volo.Abp.AspNetCore.Abstractions. In ASP.NET Core environments, HttpContextWebClientInfoProvider reads from HttpContext.Connection.RemoteIpAddress. In non-web scenarios, the default NullWebClientInfoProvider returns null, and using PartitionByClientIp() will throw an AbpException. Use PartitionByParameter() to pass the IP explicitly in non-web contexts.

Error response

On limit exceeded, throws AbpOperationRateLimitingException which is serialized to a standard ABP error response with data containing RetryAfter, RetryAfterSeconds, WindowDescription, CurrentCount, MaxCount, and RemainingCount.

Copilot AI review requested due to automatic review settings March 6, 2026 04:17
@maliming maliming added this to the 10.3-preview milestone Mar 6, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new operation-level (non-HTTP) rate limiting module to ABP (Volo.Abp.OperationRateLimit) intended to be called explicitly from application/domain code, backed by a distributed-cache store and surfaced via a dedicated exception (HTTP 429 when used in web apps). It also introduces a client IP abstraction in Volo.Abp.AspNetCore.Abstractions with an ASP.NET Core HttpContext implementation in Volo.Abp.AspNetCore.

Changes:

  • Introduces Volo.Abp.OperationRateLimit module (policies/rules, checker, distributed-cache store, localization, exception/error codes).
  • Adds IClientIpAddressProvider abstraction + default null provider, and HttpContextClientIpAddressProvider replacement.
  • Adds a comprehensive test project for the new module and wires the new projects into solution/packaging.

Reviewed changes

Copilot reviewed 70 out of 70 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
nupkg/common.ps1 Includes the new OperationRateLimit project in packaging.
framework/test/Volo.Abp.OperationRateLimit.Tests/Volo/Abp/OperationRateLimit/OperationRateLimitTestBase.cs Test base for OperationRateLimit integration tests.
framework/test/Volo.Abp.OperationRateLimit.Tests/Volo/Abp/OperationRateLimit/OperationRateLimitPolicyBuilder_Tests.cs Tests for policy builder behavior/validation.
framework/test/Volo.Abp.OperationRateLimit.Tests/Volo/Abp/OperationRateLimit/OperationRateLimitMultiTenant_Tests.cs Tests tenant isolation vs global sharing behavior.
framework/test/Volo.Abp.OperationRateLimit.Tests/Volo/Abp/OperationRateLimit/OperationRateLimitFrontendIntegration_Tests.cs Tests error formatting/localization and structured data for frontend usage.
framework/test/Volo.Abp.OperationRateLimit.Tests/Volo/Abp/OperationRateLimit/OperationRateLimitChecker_Tests.cs End-to-end checker behavior tests (composite rules, no-waste, reset, etc.).
framework/test/Volo.Abp.OperationRateLimit.Tests/Volo/Abp/OperationRateLimit/OperationRateLimitCheckerFixes_Tests.cs Regression tests for Phase1 aggregation and Phase2 race behavior.
framework/test/Volo.Abp.OperationRateLimit.Tests/Volo/Abp/OperationRateLimit/DistributedCacheOperationRateLimitStore_Tests.cs Tests for distributed-cache-backed store semantics.
framework/test/Volo.Abp.OperationRateLimit.Tests/Volo/Abp/OperationRateLimit/AbpOperationRateLimitTestModule.cs Test module configuring sample policies + mocked client IP provider.
framework/test/Volo.Abp.OperationRateLimit.Tests/Volo/Abp/OperationRateLimit/AbpOperationRateLimitPhase2RaceTestModule.cs Test module with store replacement to simulate Phase2 race conditions.
framework/test/Volo.Abp.OperationRateLimit.Tests/Volo/Abp/OperationRateLimit/AbpOperationRateLimitException_Tests.cs Tests for exception status code, code, and data payload.
framework/test/Volo.Abp.OperationRateLimit.Tests/Volo.Abp.OperationRateLimit.Tests.csproj Adds new test project.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/OperationRateLimitStoreResult.cs Store result DTO (allowed/count/retry-after).
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/OperationRateLimitRuleResult.cs Per-rule evaluation result DTO.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/OperationRateLimitRuleDefinition.cs Rule definition (window/max/partition/multi-tenant).
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/OperationRateLimitRuleBuilder.cs Fluent builder for defining rules.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/OperationRateLimitResult.cs Aggregated policy evaluation result DTO (incl. per-rule results).
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/OperationRateLimitPolicyBuilder.cs Fluent builder for policies incl. duplicate detection.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/OperationRateLimitPolicy.cs Built policy object holding rules + custom rule types.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/OperationRateLimitPartitionType.cs Partition type enum.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/OperationRateLimitContext.cs Context (parameter, extra properties, service provider).
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/OperationRateLimitChecker.cs Main checker orchestration (Phase1 check / Phase2 acquire / aggregation).
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/OperationRateLimitCacheItem.cs Distributed-cache entry shape for fixed-window counts.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/ar.json Arabic localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/cs.json Czech localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/de.json German localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/el.json Greek localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/en.json English localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/en-GB.json en-GB localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/es.json Spanish localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/fa.json Persian localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/fi.json Finnish localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/fr.json French localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/hi.json Hindi localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/hr.json Croatian localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/hu.json Hungarian localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/is.json Icelandic localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/it.json Italian localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/nl.json Dutch localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/pl-PL.json Polish localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/pt-BR.json Portuguese (Brazil) localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/ro-RO.json Romanian localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/ru.json Russian localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/sk.json Slovak localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/sl.json Slovenian localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/sv.json Swedish localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/tr.json Turkish localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/vi.json Vietnamese localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/Localization/zh-Hans.json Simplified Chinese localization for exception + formatter text.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/IOperationRateLimitStore.cs Store abstraction (increment/get/reset).
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/IOperationRateLimitRule.cs Rule abstraction (check/acquire/reset).
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/IOperationRateLimitPolicyProvider.cs Policy provider abstraction.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/IOperationRateLimitFormatter.cs Formatter abstraction for human-readable durations.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/IOperationRateLimitChecker.cs Checker abstraction for consumers.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/FixedWindowOperationRateLimitRule.cs Built-in fixed-window rule implementation + key building.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/DistributedCacheOperationRateLimitStore.cs Distributed-cache-backed store with distributed locking.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/DefaultOperationRateLimitPolicyProvider.cs Default policy provider based on options.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/DefaultOperationRateLimitFormatter.cs Default localized duration formatter implementation.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/AbpOperationRateLimitResource.cs Localization resource marker.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/AbpOperationRateLimitOptions.cs Options container and policy registration entry point.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/AbpOperationRateLimitModule.cs Module wiring (VFS + localization + exception code mapping).
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/AbpOperationRateLimitException.cs Dedicated exception with HTTP 429 and structured data.
framework/src/Volo.Abp.OperationRateLimit/Volo/Abp/OperationRateLimit/AbpOperationRateLimitErrorCodes.cs Default error code constant.
framework/src/Volo.Abp.OperationRateLimit/Volo.Abp.OperationRateLimit.csproj New package project + embedded localization resources.
framework/src/Volo.Abp.OperationRateLimit/FodyWeavers.xml ConfigureAwait weaving config for the new module.
framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/ClientIpAddress/HttpContextClientIpAddressProvider.cs ASP.NET Core implementation of client IP provider (replaces default).
framework/src/Volo.Abp.AspNetCore.Abstractions/Volo/Abp/AspNetCore/ClientIpAddress/NullClientIpAddressProvider.cs Default null provider implementation.
framework/src/Volo.Abp.AspNetCore.Abstractions/Volo/Abp/AspNetCore/ClientIpAddress/IClientIpAddressProvider.cs New client IP provider abstraction.
framework/src/Volo.Abp.AspNetCore.Abstractions/Volo/Abp/AspNetCore/AbpAspNetCoreAbstractionsModule.cs Registers the new default client IP provider.
framework/Volo.Abp.slnx Adds the new project + test project to the solution.

@maliming maliming marked this pull request as draft March 6, 2026 05:14
@maliming maliming changed the title Add Volo.Abp.OperationRateLimit module Add Volo.Abp.OperationRateLimiting module Mar 6, 2026
@maliming maliming marked this pull request as ready for review March 6, 2026 08:31
@maliming maliming requested a review from Copilot March 6, 2026 08:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 69 out of 69 changed files in this pull request and generated 2 comments.

Comment thread nupkg/common.ps1 Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 69 out of 69 changed files in this pull request and generated 6 comments.

Comment thread docs/en/framework/infrastructure/operation-rate-limiting.md
Comment thread docs/en/framework/infrastructure/operation-rate-limiting.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 69 out of 69 changed files in this pull request and generated 4 comments.

Comment thread docs/en/framework/infrastructure/operation-rate-limiting.md
@maliming maliming requested review from EngincanV and hikalkan March 6, 2026 10:39
Comment thread docs/en/docs-nav.json Outdated
Comment thread docs/en/framework/infrastructure/operation-rate-limiting.md Outdated
@hikalkan hikalkan merged commit 2f78935 into dev Mar 8, 2026
3 checks passed
@hikalkan hikalkan deleted the Operation-Rate-Limiting branch March 8, 2026 12:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Operation Rate Limiting

3 participants