NoMeans429 1.0.1
dotnet add package NoMeans429 --version 1.0.1
NuGet\Install-Package NoMeans429 -Version 1.0.1
<PackageReference Include="NoMeans429" Version="1.0.1" />
<PackageVersion Include="NoMeans429" Version="1.0.1" />
<PackageReference Include="NoMeans429" />
paket add NoMeans429 --version 1.0.1
#r "nuget: NoMeans429, 1.0.1"
#:package NoMeans429@1.0.1
#addin nuget:?package=NoMeans429&version=1.0.1
#tool nuget:?package=NoMeans429&version=1.0.1
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
- Policy Precedence
- Usage Philosophy
- Example Usage
- Configuration Options
- Policy Sources
- Client-Based Rate Limiting
- Endpoint-Based Rate Limiting
- IP-Based Rate Limiting
- Global Rate Limiting
- Caching
- Extensibility
- Testing and Examples
- NuGet Package and Documentation
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 (fromDynamicEndpointPolicyJsonPath
). - If none found, falls back to client, IP, or global policies.
Example:
[EndpointRateLimit(PerMinute = 3)]
is set onGET /api/orders
.StaticEndpointPolicies
definesGET /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 clientabc123
to 5 per minute.DynamicClientPolicyJsonPath
sets clientabc123
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 IP1.2.3.4
to 5 per minute.DynamicIpPolicyJsonPath
sets IP1.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 | Versions Compatible and additional computed target framework versions. |
---|---|
.NET Framework | net48 is compatible. net481 was computed. |
-
.NETFramework 4.8
- Microsoft.AspNet.WebApi.Client (>= 6.0.0)
- Microsoft.AspNet.WebApi.Core (>= 5.3.0)
- Microsoft.Bcl.AsyncInterfaces (>= 9.0.7)
- Microsoft.Extensions.Caching.Abstractions (>= 9.0.7)
- Microsoft.Extensions.Caching.Memory (>= 9.0.7)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.7)
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.7)
- Microsoft.Extensions.Options (>= 9.0.7)
- Microsoft.Extensions.Primitives (>= 9.0.7)
- Newtonsoft.Json (>= 13.0.3)
- Newtonsoft.Json.Bson (>= 1.0.2)
- Pipelines.Sockets.Unofficial (>= 2.2.8)
- StackExchange.Redis (>= 2.8.41)
- System.Buffers (>= 4.6.1)
- System.Diagnostics.DiagnosticSource (>= 9.0.7)
- System.IO.Compression (>= 4.3.0)
- System.IO.Pipelines (>= 5.0.1)
- System.Memory (>= 4.6.3)
- System.Numerics.Vectors (>= 4.6.1)
- System.Runtime.CompilerServices.Unsafe (>= 6.1.2)
- System.Threading.Channels (>= 5.0.0)
- System.Threading.Tasks.Extensions (>= 4.6.3)
- System.ValueTuple (>= 4.5.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Initial release: Flexible, extensible rate limiting for .NET WebAPI with static/dynamic policies and pluggable cache providers.