EonaCat.Web.RateLimiter 1.0.2

The ID prefix of this package has been reserved for one of the owners of this package by NuGet.org. Prefix Reserved
dotnet add package EonaCat.Web.RateLimiter --version 1.0.2
NuGet\Install-Package EonaCat.Web.RateLimiter -Version 1.0.2
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="EonaCat.Web.RateLimiter" Version="1.0.2" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add EonaCat.Web.RateLimiter --version 1.0.2
#r "nuget: EonaCat.Web.RateLimiter, 1.0.2"
#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.
// Install EonaCat.Web.RateLimiter as a Cake Addin
#addin nuget:?package=EonaCat.Web.RateLimiter&version=1.0.2

// Install EonaCat.Web.RateLimiter as a Cake Tool
#tool nuget:?package=EonaCat.Web.RateLimiter&version=1.0.2

EonaCat.Web.RateLimiter

Configure the service with the default options:

public void ConfigureServices(IServiceCollection services)
{
	services.UseWebRateLimiter();
}

or

builder.Services.UseWebRateLimiter();

DEFAULT: 10 requests can be called every 10 seconds.

Configure the service with given options:

var options = new RateLimiterOptions();
options.OutputLimitMessageAsHtml = false;
options.OutputLimitMessageAsJson = true;
options.AddDefaultConfiguration(config =>
	// Max 10 requests every 10 seconds
    config.AddIpResolver().AddRule(10, TimeSpan.FromSeconds(10))
	// Max 60 requests every 1 minute
	config.AddIpResolver().AddRule(60, TimeSpan.FromMinutes(1))
);

builder.Services.UseWebRateLimiter(options);

Configure the service using an action expression: Below you can find an example configuration.

builder.Services.UseWebRateLimiter(options =>
{
    // Configures the default RateLimitConfiguration
    options.AddDefaultConfiguration(rateLimitConfiguration =>
    {
        // Add IpResolver
        rateLimitConfiguration.AddIpResolver()
		// Add rule for all ipAddresses with Max 10 requests every 10 seconds
		.AddRule(10, TimeSpan.FromSeconds(10));
		// Add a custom rule for a specific ipAddress with Max 60 requests every 10 
		// seconds
		.AddCustomRule("192.168.1.10", 60, TimeSpan.FromSeconds(10))
		// Put an ipAddress in the allowList which will NOT be rateLimited
		.Allow.IP("127.0.0.1", "::1")
    });
});

If you configure the service as an action expression make sure you also initiate the cache provider (Non action expression already adds a memory cache):

Memory cache:

builder.Services.AddMemoryCache();	# MemoryCache for the services
builder.AddMemoryStore(); # MemoryCache for the builder

Distributed Memory cache:

builder.Services.AddDistributedMemoryCache();	# DistributedMemoryCache for the services
builder.AddDistributedMemoryCache();	# DistributedMemoryCache for the builder

Add the middleware:

Warning: Be sure to add the EonaCat.Web.RateLimiter middleWare AFTER the Routing middleWare. If the chain is not in this order then the rateLimiter will fail to retrieve its endpoint information.

app.UseRouting();
app.UseWebRateLimiter();
How to add RateLimit on Controller:
// RateLimit
[RateLimit]
[ApiController]
public class ApiController : ControllerBase
{
    [HttpGet("ping")]
    public string GetPing()
    {
        return "Pong";
    }

    // Override rule for this action with 2 requests per second
    [RateLimit(PerSecond = 2)]
    [HttpGet("Heavy")]
    public string Heavy()
    {
        return "HEAVY METAL!";
    }

    // Disable rateLimit for this action
    [DisableRateLimit]
    [HttpGet("Spam")]
    public string[] GetSpam()
    {
        return new string[] { "Spam1", "Spam2", "Spam3", "Spam4", "Spam5" };
    }
}
How to add RateLimit on all razor endpoints:
app.MapRazorPages().RateLimit();
How to add RateLimit on a specific endpoint:
app.UseEndpoints(endpoints =>
{
    endpoints.MapGet("/Heavy", context =>
    {
        return context.Response.WriteAsync("Metal!");
    })
    // RateLimit "/Heavy" endpoint with default configuration
    .RateLimit();

    endpoints.MapGet("/Whoami", context =>
    {
        return context.Response.WriteAsync("NOOB");
    })
    // RateLimit "/Whoami" endpoint and override rule for default configuration
    .RateLimit(perSecond: 1);
});

Available attributes

  • [RateLimit] ⇒ RateLimits the controller
  • [EnableRateLimit] ⇒ Enables the RateLimit for a specific method
  • [DisableRateLimit] ⇒ Disables the RateLimit for a specific method

Information about the RateLimiterOptions:

LimitMessage: The message which needs to be shown to the user when the rate limit has exceeded.

WriteLimitMessageToResponse: Determines if we need to write the limit message to the response. (Default: true)

WriteLimitMessageStatusCodeToResponse: Determines if we need to write the Statuscode 'TooManyRequests' 429 to the response. (Default: true)

OutputLimitMessageAsHtml: Determines if we need to output the limitMessage as Html. (Default:true)

OutputLimitMessageAsJson: Determines if we need to output the limitMessage as Json.

OutputLimitMessageAsXml: Determines if we need to output the limitMessage as Xml.

OutputHtmlTitle: Determines if we need to output an Html Title. (Default :true)

LimitMessageHtmlTitle: Limit message Html Title to display.

Information about the RateLimiter Configuration Options:

AddIpResolver().AddRule(): Adds a rule for the rateLimitConfiguration with a requestLimit and timeWindow for the total amount of requests.

AddIpResolver().AddCustomRule(): Adds a custom rule for the rateLimitConfiguration with a requestLimit and timeWindow for the total amount of requests which is only valid for a specific entity (ipAddress in this case).

AddIpResolver().AddCustomRules(): Adds an array of custom rules for the rateLimitConfiguration with a requestLimit and timeWindow for the total amount of requests which is only valid for the entity specified in the customRule (ipAddress in this case).

Allow.IP("127.0.0.1", "::1"): ignores requests coming from IP 127.0.0.1 and ::1.

Allow.User("Admin"): ignores requests coming from the logged in user named Admin.

Allow.Host("api.EonaCat.com"): ignores requests coming from the Host header "api.EonaCat.com"

Resolvers for rules:

  • AccessTokenResolver ⇒ Can be used to resolve AccesToken from Authentication Providers (for example OAuth2)
  • HostResolver ⇒ Can be used to resolve a specific host based on it's hostHeader
  • IpResolver ⇒ Can be used to resolve an ipAddress
  • NoResolver ⇒ No resolver set (default resolver)
  • TypeResolver ⇒ Can be used to resolve a serviceCollection by it's type
  • UsernameResolver ⇒ Can be used to resolve a Username based on it's claim principal identity
Create your own resolver:

Implement the interface IResolver or IAllowResolver

Example of the HostResolver:

public class HostResolver : IAllowListResolver
    {
        private const string Unknown = "[Unknown]";

        private HostResolver()
        {

        }

        public static HostResolver Instance { get; } = new HostResolver();

        public bool Matches(string scope, string allow)
        {
            return scope.Equals(allow, StringComparison.InvariantCultureIgnoreCase);
        }

        public ValueTask<string> ResolveAsync(HttpContext httpContext)
        {
            if (httpContext.Request.Host.HasValue)
            {
                return new ValueTask<string>(httpContext.Request.Host.Value);
            }
            else
            {
                return new ValueTask<string>(Unknown);
            }
        }
    }

Bind to responseCreation event:

You can also bind to a responseCreation event. This event will get triggered everytime a request limit is reached. (also triggers when WriteLimitMessageToResponse is disabled)

Please be sure to disable WriteLimitMessageToResponse if you are going to write your own custom response to prevent two response messages written.

RateLimiterMiddleware.OnLimitResponseCreated += RateLimiterMiddleware_OnLimitResponseCreatedAsync;
async void RateLimiterMiddleware_OnLimitResponseCreatedAsync(object? sender, HttpContext httpContext)
{
    await httpContext.Response.WriteAsync("THIS IS MY CUSTOM RATE LIMIT MESSAGE");
}
Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows 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.2 297 1/15/2023