Skip to content

Commit

Permalink
Feature/apply as middleware (#22)
Browse files Browse the repository at this point in the history
Feature/apply as middleware
  • Loading branch information
ejcoyle88 authored Nov 13, 2019
2 parents c568362 + 5109c16 commit fbbd6cc
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 19 deletions.
4 changes: 2 additions & 2 deletions KnowYourLimits.AspNetCore/RateLimiterMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ public class RateLimiterMiddleware<TClientIdentity>
where TClientIdentity : IClientIdentity, new()
{
private readonly RequestDelegate _next;
private readonly IRateLimitStrategy<IClientIdentity> _rateLimitStrategy;
private readonly IRateLimitStrategy<TClientIdentity> _rateLimitStrategy;

public RateLimiterMiddleware(RequestDelegate next, IRateLimitStrategy<IClientIdentity> rateLimitStrategy)
public RateLimiterMiddleware(RequestDelegate next, IRateLimitStrategy<TClientIdentity> rateLimitStrategy)
{
_next = next;
_rateLimitStrategy = rateLimitStrategy;
Expand Down
31 changes: 24 additions & 7 deletions KnowYourLimits.AspNetCore/RateLimiterMiddlewareExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,40 @@
using KnowYourLimits.Identity;
using KnowYourLimits.Strategies;
using KnowYourLimits.Strategies.LeakyBucket;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;

// These are all used outside of this lib, and so are 'unused'
// ReSharper disable UnusedMember.Global

namespace KnowYourLimits.AspNetCore
{
// ReSharper disable once UnusedMember.Global
public static class RateLimiterMiddlewareExtensions
{
// ReSharper disable once UnusedMember.Global
public static void UseRateLimiting<TClientIdentity>(this IApplicationBuilder applicationBuilder,
IRateLimitStrategy<TClientIdentity> rateLimitStrategy)
public static void UseRateLimiting<TClientIdentity>(this IApplicationBuilder applicationBuilder)
where TClientIdentity : IClientIdentity, new()
{
applicationBuilder.UseMiddleware<RateLimiterMiddleware<TClientIdentity>>();
}

public static void AddRateLimiting<TClientIdentity>(
this IServiceCollection serviceCollection,
IRateLimitStrategy<TClientIdentity> strategy)
where TClientIdentity : IClientIdentity, new()
{
if (rateLimitStrategy.IdentityProvider == null)
if (strategy.IdentityProvider == null)
{
rateLimitStrategy.IdentityProvider = new IpClientIdentityProvider<TClientIdentity>();
strategy.IdentityProvider = new IpClientIdentityProvider<TClientIdentity>();
}

applicationBuilder.UseMiddleware<RateLimiterMiddleware<TClientIdentity>>(rateLimitStrategy);
serviceCollection.AddSingleton(strategy);
}

public static void AddLeakyBucketRateLimiting(
this IServiceCollection serviceCollection,
LeakyBucketConfiguration config)
{
serviceCollection.AddRateLimiting(new LeakyBucketRateLimitStrategy(config));
}
}
}
7 changes: 7 additions & 0 deletions KnowYourLimits.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KnowYourLimits.AspNetCore",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KnowYourLimits.UnitTests", "KnowYourLimits.UnitTests\KnowYourLimits.UnitTests.csproj", "{D8B3BB5F-AB4F-4CF2-84C5-2439BB8546CB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentation", "{AEB63280-2D5C-4A2C-BC2D-A2D7AC6F3871}"
ProjectSection(SolutionItems) = preProject
README.md = README.md
CODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md
LICENSE = LICENSE
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down
32 changes: 22 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,29 @@ The middleware should be attached to the application as high in the order as pos
For example, to configure the rate limiter to allow 4 requests per second, with a maximum of 100 requests, see below:

```cs
var rateLimitingConfiguration = new LeakyBucketConfiguration
public void ConfigureServices(IServiceCollection services)
{
MaxRequests = 100,
LeakRate = TimeSpan.FromSeconds(1),
LeakAmount = 4,
IdentityProvider = new CustomIdentityProvider(), // If not set, defaults to using the remote address
EnableHeaders = true, // If true, a set of headers, documented below, will be returned on all responses describing the rate limits
HeaderPrefix = "X-MYORG-" // This will be prepended to all generated headers.
};

app.UseRateLimiting(new LeakyBucketRateLimitStrategy(rateLimitingConfiguration));
...
var rateLimitingConfiguration = new LeakyBucketConfiguration
{
MaxRequests = 100,
LeakRate = TimeSpan.FromSeconds(1),
LeakAmount = 4,
IdentityProvider = new CustomIdentityProvider(), // If not set, defaults to using the remote address
EnableHeaders = true, // If true, a set of headers, documented below, will be returned on all responses describing the rate limits
HeaderPrefix = "X-MYORG-" // This will be prepended to all generated headers.
};
services.AddLeakyBucketRateLimiting(rateLimitingConfiguration);
...
}


public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IApiVersionDescriptionProvider provider)
{
...
app.UseRateLimiting<LeakyBucketClientIdentity>();
...
}
```

By default client requests will be identified using the remote address of the request. To implement a custom identity provider, implement the `IClientIdentityProvider` interface and pass it in to the configuration.
Expand Down

0 comments on commit fbbd6cc

Please sign in to comment.