NoMeans429 1.0.1

dotnet add package NoMeans429 --version 1.0.1
                    
NuGet\Install-Package NoMeans429 -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NoMeans429" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NoMeans429" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="NoMeans429" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NoMeans429 --version 1.0.1
                    
#r "nuget: NoMeans429, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NoMeans429@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NoMeans429&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=NoMeans429&version=1.0.1
                    
Install as a Cake Tool

NoMeans429 – Flexible Rate Limiter for .NET WebAPI

NoMeans429 is a plug-and-play, highly extensible rate limiting NuGet package for .NET Framework WebAPI. It supports global, IP, endpoint, and client-based throttling with both static and dynamic policy sources, claim-based client limits, and pluggable cache (memory or Redis). All business logic is encapsulated inside the package—minimal API-side configuration is needed.

Table of Contents

Features

  • Global, IP, endpoint, and client-based rate limiting
  • Attribute-based per-endpoint overrides
  • Static and dynamic (JSON) policy sources
  • Claim-based client throttling (multiple claims supported)
  • Pluggable cache provider (in-memory or Redis)
  • Composite and fallback policy resolution
  • Swagger and health check bypass
  • Plug-and-play: all logic in the NuGet, minimal API code
  • English docs & XML summaries for public APIs

Policy Precedence

When multiple rate limit policies could apply to a request (e.g. the same IP, endpoint, or client is defined in both static and dynamic sources), the following precedence rules are used:

1. Endpoint Policy Precedence

  • Highest precedence: If an endpoint has the [EndpointRateLimit] attribute, this limit is always used for that endpoint, regardless of any static or dynamic policy.
  • If no attribute is present, the system checks for a static endpoint policy (from StaticEndpointPolicies), then a dynamic endpoint policy (from DynamicEndpointPolicyJsonPath).
  • If none found, falls back to client, IP, or global policies.

Example:

  • [EndpointRateLimit(PerMinute = 3)] is set on GET /api/orders.
  • StaticEndpointPolicies defines GET /api/orders as 10 per minute.
  • Result: The attribute value (3 per minute) is enforced.

2. Client Policy Precedence

  • If a client is identified (via ID or claim), the system first checks for a static client policy (StaticClientPolicies), then a dynamic client policy (DynamicClientPolicyJsonPath), then claim-based limits (from the user's token claims).
  • If none found, falls back to IP or global policies.

Example:

  • StaticClientPolicies sets client abc123 to 5 per minute.
  • DynamicClientPolicyJsonPath sets client abc123 to 8 per minute.
  • Result: The static policy (5 per minute) is enforced.

3. IP Policy Precedence

  • If no endpoint or client policy applies, the system checks for a static IP policy (StaticIpPolicies), then a dynamic IP policy (DynamicIpPolicyJsonPath).
  • If none found, falls back to the global policy.

Example:

  • StaticIpPolicies sets IP 1.2.3.4 to 5 per minute.
  • DynamicIpPolicyJsonPath sets IP 1.2.3.4 to 10 per minute.
  • Result: The static policy (5 per minute) is enforced.

4. Global Policy

  • If no specific endpoint, client, or IP policy applies, the global policy is used as a fallback.

Usage Philosophy

  • Plug-and-play: API-side code is minimal, with maximum flexibility.
  • All business logic is encapsulated: Handler, configurator, and providers are included in the NuGet package.
  • Extensibility: New policy providers or custom logic can be easily added.

Example Usage

Below are example configurations for all supported scenarios. Each example is ready to use and includes a short explanation.

1. Global Rate Limiting

Limits all requests to a maximum per interval (e.g., per minute) regardless of IP or client.

options.GlobalPolicy = new RateLimitPolicy { PerMinute = 100 };

2. Static IP-based Rate Limiting

Define different limits for specific IP addresses using an in-memory dictionary.

options.StaticIpPolicies = new Dictionary<string, RateLimitPolicy>
{
    ["192.168.1.1"] = new RateLimitPolicy { PerMinute = 5, PerHour = 100 },
    ["10.0.0.2"] = new RateLimitPolicy { PerSecond = 2 }
};

3. Dynamic IP-based Rate Limiting (from JSON)

Load IP policies from an external JSON file at runtime.

options.DynamicIpPolicyJsonPath = @"C:\config\ipPolicies.json";

Example ipPolicies.json:

{
  "203.0.113.1": { "PerMinute": 10, "PerHour": 100 },
  "198.51.100.2": { "PerSecond": 3 }
}

4. Static Endpoint-based Rate Limiting

Set per-endpoint limits using a dictionary.

options.StaticEndpointPolicies = new Dictionary<string, RateLimitPolicy>
{
    ["/api/orders"] = new RateLimitPolicy { PerMinute = 20 },
    ["/api/products"] = new RateLimitPolicy { PerSecond = 5 }
};

5. Dynamic Endpoint-based Rate Limiting (from JSON)

Load endpoint policies from an external JSON file.

options.DynamicEndpointPolicyJsonPath = @"C:\config\endpointPolicies.json";

Example endpointPolicies.json:

{
  "/api/orders": { "PerMinute": 20 },
  "/api/products": { "PerSecond": 5 }
}

6. Static Client-based Rate Limiting

Set limits for specific clients (API keys, tokens, etc.).

options.StaticClientPolicies = new Dictionary<string, RateLimitPolicy>
{
    ["clientA"] = new RateLimitPolicy { PerMinute = 50 },
    ["clientB"] = new RateLimitPolicy { PerHour = 500 }
};

7. Dynamic Client-based Rate Limiting (from JSON)

Load client policies from an external JSON file.

options.DynamicClientPolicyJsonPath = @"C:\config\clientPolicies.json";

Example clientPolicies.json:

{
  "clientA": { "PerMinute": 50 },
  "clientB": { "PerHour": 500 }
}

8. Claim-based Client Rate Limiting

Map claims in the user's token to rate limit intervals for per-user or per-role throttling.

options.ClientClaimMappings = new Dictionary<string, string>
{
    ["rate_min"] = "PerMinute",
    ["rate_hour"] = "PerHour",
    ["rate_day"] = "PerDay"
};
  • If a claim value is -1 or null, it is ignored (unlimited for that interval).

How are claim-based rate limits set?
The actual limit values (e.g., PerMinute, PerHour, PerDay) are read directly from the user's token claims. Your authentication/identity system must include these claims in each user's access token. For example, a JWT might contain:

{
  "sub": "user123",
  "rate_min": 20,
  "rate_hour": 100,
  "rate_day": 500
}

No static configuration is needed for these limits in your API; they are dynamic and user-specific.

9. Attribute-based Per-Endpoint Limiting

Override rate limits for specific controller actions using an attribute.

[EndpointRateLimit(PerSecond = 2, PerMinute = 10, Enabled = true)]
public IHttpActionResult Get() { ... }

10. Memory Cache Provider (Default)

By default, the rate limiter uses in-memory caching via Microsoft.Extensions.Caching.Memory. No extra configuration required; works out of the box.

Explicitly set the memory cache provider:

using Microsoft.Extensions.Caching.Memory;
using NoMeans429.Providers;

options.CacheProvider = new MemoryCacheRateLimitProvider(new MemoryCache(new MemoryCacheOptions()));

This is useful if you want to customize memory cache options or manage the cache instance yourself.

11. Custom Cache Provider

You can implement your own cache provider (for example, to use a distributed cache or another backend). All providers must implement the IRateLimitCacheProvider interface:

using NoMeans429.Providers;

public class MyCustomCacheProvider : IRateLimitCacheProvider
{
    public Task<int?> GetAsync(string key)
    {
        // Your logic here
        return Task.FromResult<int?>(null);
    }
    public Task SetAsync(string key, int value, TimeSpan expiration)
    {
        // Your logic here
        return Task.CompletedTask;
    }
    public Task<int> IncrementAsync(string key, TimeSpan expiration)
    {
        // Your logic here
        return Task.FromResult(1);
    }
}

// Usage:
options.CacheProvider = new MyCustomCacheProvider();

12. Redis Cache Provider

Use Redis for distributed rate limiting.

options.CacheProvider = new RedisRateLimitCacheProvider("localhost:6379");

12. Excluding Swagger, Health, or Custom Paths

Bypass rate limiting for specific endpoints.

options.EnableSwaggerBypass = true;
options.ExcludedPaths = new List<string> { "/health", "/metrics" };

13. Custom Policy Provider

Implement your own IRateLimitPolicyProvider for advanced scenarios (e.g., database, API, etc.).

public class MyCustomPolicyProvider : IRateLimitPolicyProvider
{
    public RateLimitPolicy GetPolicy(string key)
    {
        // Custom logic here
    }
}
options.CustomPolicyProvider = new MyCustomPolicyProvider();

14. Full Example: All Features Combined

using NoMeans429;
using NoMeans429.Policies;
using NoMeans429.Providers;
using NoMeans429.Middleware;

public static void Register(HttpConfiguration config)
{
    var options = new RateLimitOptions
    {
        StaticIpPolicies = new Dictionary<string, RateLimitPolicy> { ["127.0.0.1"] = new RateLimitPolicy { PerMinute = 10 } },
        DynamicIpPolicyJsonPath = @"C:\\config\\ipPolicies.json",
        StaticEndpointPolicies = new Dictionary<string, RateLimitPolicy> { ["/api/orders"] = new RateLimitPolicy { PerMinute = 20 } },
        DynamicEndpointPolicyJsonPath = @"C:\\config\\endpointPolicies.json",
        StaticClientPolicies = new Dictionary<string, RateLimitPolicy> { ["clientA"] = new RateLimitPolicy { PerMinute = 50 } },
        DynamicClientPolicyJsonPath = @"C:\\config\\clientPolicies.json",
        GlobalPolicy = new RateLimitPolicy { PerMinute = 100 },
        EnableSwaggerBypass = true,
        ExcludedPaths = new List<string> { "/health" },
        ClientClaimMappings = new Dictionary<string, string> { ["rate_min"] = "PerMinute" },
        CacheProvider = new RedisRateLimitCacheProvider("localhost:6379")
    };
    RateLimitConfigurator.Configure(config, options);
}

Configuration Options

  • StaticIpPolicies: A dictionary of IP addresses and their corresponding rate limit policies.
  • DynamicIpPolicyJsonPath: The path to a JSON file containing dynamic IP policies.
  • GlobalPolicy: The global rate limit policy.
  • EnableSwaggerBypass: A flag to enable or disable Swagger bypass.
  • ExcludedPaths: A list of paths to exclude from rate limiting.

Policy Sources

  • Static Policy Source: A dictionary of IP addresses and their corresponding rate limit policies.
  • Dynamic Policy Source: A JSON file containing dynamic IP policies.

Client-Based Rate Limiting

  • Claim-Based Client Throttling: Rate limiting based on claims in the client's token.
  • Multiple Claims Support: Support for multiple claims in the client's token.

Endpoint-Based Rate Limiting

  • Attribute-Based Per-Endpoint Overrides: Override rate limit policies for specific endpoints using attributes.
  • Endpoint Configuration: Configure rate limit policies for specific endpoints.

IP-Based Rate Limiting

  • IP-Based Rate Limiting: Rate limiting based on the client's IP address.
  • Static and Dynamic Policy Sources: Support for both static and dynamic policy sources.

Global Rate Limiting

  • Global Rate Limit Policy: A global rate limit policy that applies to all clients.

Caching

  • Pluggable Cache Provider: Support for pluggable cache providers (in-memory or Redis).

Extensibility

  • New Policy Providers: Easily add new policy providers.
  • Custom Logic: Easily add custom logic.

Testing and Examples

  • Example Config and Tests: Included example config and tests.
  • Quick Start Examples: Included quick start examples.

NuGet Package and Documentation

  • Easy Installation: Easy installation via NuGet package.
  • Clear Documentation: Clear and concise documentation.
Product Compatible and additional computed target framework versions.
.NET Framework net48 is compatible.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 106 7/11/2025
1.0.0 103 7/11/2025

Initial release: Flexible, extensible rate limiting for .NET WebAPI with static/dynamic policies and pluggable cache providers.