-
Notifications
You must be signed in to change notification settings - Fork 10.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
API additions for RateLimitingMiddleware #42667
Comments
I like the idea of skipping the middleware suggested in #41667 (comment) |
Thank you for submitting this for API review. This will be reviewed by @dotnet/aspnet-api-review at the next meeting of the ASP.NET Core API Review group. Please ensure you take a look at the API review process documentation and ensure that:
|
Meeting notes:
|
This looks great so far 😄 |
How about this one: + public interface IDisableRateLimiterMetadata
+ {
+ bool IsDisabled { get; }
+ } This is according to the Guidelines and can be overriden if necessary.
Also
Can it be |
Agree with @Kahbazi on the disable attribute. We need attributes for anything we have methods for. |
Why does the |
I'm just quoting the Guidance which exists in ASP.NET Core Docs
And this could be done if the metadata has a property. public class SuppressDisableateLimitAttribute : Attribute, IDisableRateLimiterMetadata
{
public bool IsDisabled => false;
}
[DisableRateLimit]
public class MyController : Controller
{
public void Unlimit() { }
[SuppressDisableateLimit]
public void Limited() { }
} |
This example applies to route groups as well |
@Kahbazi hmm, do we have an example of us actually doing that somewhere in the framework? We don't follow that for In your example, am I understanding correctly that this is supposed to facilitate re-enabling rate limiting when other metadata for the endpoint already disables it? How do we do that in the AuthZ system? The code seems to suggest we just ignore any AuthZ failures if the allow anonymous metadata is present at all. |
@DamianEdwards You are right. This is not how it's done today in AUTH or CORS. Now if there's an |
Runtime API proposal: dotnet/runtime#72389 |
namespace Microsoft.AspNetCore.RateLimiting
+ public interface IRateLimiterMetadata
+ {
+ string PolicyName { get; }
+ }
+ public class RateLimiterMetadata : IRateLimiterMetadata
+ {
+ public RequireRateLimiterMetadata (string policyName)
+ public string PolicyName { get; }
+ }
+ public interface IDisableRateLimiterMetadata
+ {
+ }
+ public class DisableRateLimiterMetadata : IDisableRateLimiterMetadata
+ {
+ public DisableRateLimiterMetadata ()
+ }
+ public class EnableRateLimitingAttribute : Attribute, IRateLimiterMetadata
+ {
+ public EnableRateLimitingAttribute (string policyName)
+ string PolicyName { get; }
+ }
+ public class DisableRateLimitingAttribute : Attribute, IDisableRateLimiterMetadata
+ {
+ public DisableRateLimitingAttribute ()
+ }
+ public interface IRateLimiterPolicyMetadata<TPartitionKey>
+ {
+ IRateLimiterPolicy<TPartitionKey> Policy { get; }
+ }
+ public class RateLimiterPolicyMetadata<TPartitionKey> : IRateLimiterPolicyMetadata<TPartitionKey>
+ {
+ public RateLimiterPolicyMetadata (IRateLimiterPolicy<TPartitionKey> policy)
+ public IRateLimiterPolicy<TPartitionKey> Policy { get; }
+ }
namespace Microsoft.AspNetCore.Builder
+ public static class RateLimiterServiceCollectionExtensions
+ {
+ public static IServiceCollection AddRateLimiter(this IServiceCollection services, Action<RateLimiterOptions > configureOptions)
+ }
public static class RateLimiterOptionsExtensions
{
- public static RateLimiterOptions AddNoLimiter(this RateLimiterOptions options, string policyName)
- public static RateLimiterOptions AddTokenBucketLimiter(this RateLimiterOptions options, string policyName, TokenBucketRateLimiterOptions tokenBucketRateLimiterOptions)
+ public static RateLimiterOptions AddTokenBucketLimiter(this RateLimiterOptions options, string policyName, Action<TokenBucketRateLimiterOptions> configureOptions)
- public static RateLimiterOptions AddFixedWindowLimiter(this RateLimiterOptions options, string policyName, FixedWindowRateLimiterOptions fixedWindowRateLimiterOptions)
+ public static RateLimiterOptions AddFixedWindowLimiter(this RateLimiterOptions options, string policyName, Action< FixedWindowRateLimiterOptions> configureOptions)
- public static RateLimiterOptions AddSlidingWindowLimiter(this RateLimiterOptions options, string policyName, SlidingWindowRateLimiterOptions slidingWindowRateLimiterOptions)
+ public static RateLimiterOptions AddSlidingWindowLimiter(this RateLimiterOptions options, string policyName, Action< SlidingWindowRateLimiterOptions> configureOptions)
- public static RateLimiterOptions AddConcurrencyLimiter(this RateLimiterOptions options, string policyName, ConcurrencyLimiterOptions concurrencyLimiterOptions)
+ public static RateLimiterOptions AddConcurrencyLimiter(this RateLimiterOptions options, string policyName, Action< ConcurrencyLimiterOptions> configureOptions)
}
public static class RateLimiterEndpointConventionBuilderExtensions
{
+ public static TBuilder DisableRateLimiting<TBuilder>(this TBuilder builder) where TBuilder : IEndpointConventionBuilder
+ public static TBuilder RequireRateLimiting<TBuilder, TPartitionKey>(this TBuilder builder, IRateLimiterPolicy<TPartitionKey> policy) where TBuilder : IEndpointConventionBuilder
}
|
Thank you for submitting this for API review. This will be reviewed by @dotnet/aspnet-api-review at the next meeting of the ASP.NET Core API Review group. Please ensure you take a look at the API review process documentation and ensure that:
|
|
Yes, the only difference is that one is an attribute. We can probably combine them as you suggested in
Right now, the first one added gets used. We don't yet throw an exception when multiple get added to the same endpoint, but we could start doing so here: aspnetcore/src/Middleware/RateLimiting/src/RateLimiterEndpointConventionBuilderExtensions.cs Lines 25 to 28 in 1380236
Though that gets less consistent when the metadata & attribute are combined.
I'm leaning towards following the CORS pattern, but I'm open to the change. We'll discuss in API review. |
The attribute should be a concrete type not an interface so I assume it should be: public class EnableRateLimitingAttribute : Attribute, IRateLimiterMetadata |
+ public static RateLimiterOptions AddTokenBucketLimiter(this RateLimiterOptions options, string policyName, Action<TokenBucketRateLimiterOptions> configureOptions)
+ public static RateLimiterOptions AddTokenBucketLimiter(this RateLimiterOptions options, string policyName, Action<TokenBucketRateLimiterOptions, HttpContext> configureOptions) Also I think it's useful to have an overload with rateLimiterOptions.AddTokenBucketLimiter("policy", (options, context) =>
{
options.TokensPerPeriod = context.GetEndpoint().Metadata.GetMetadata<MyLimiterMetadata>().TokensPerPeriod;
}; |
API Review Notes:
namespace Microsoft.AspNetCore.RateLimiting
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
+ public sealed class EnableRateLimitingAttribute : Attribute
+ {
+ public EnableRateLimitingAttribute(string policyName);
+ string PolicyName { get; }
+ }
+
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
+ public sealed class DisableRateLimitingAttribute : Attribute
+ {
+ public DisableRateLimitingAttribute();
+ }
namespace Microsoft.AspNetCore.Builder
+ public static class RateLimiterServiceCollectionExtensions
+ {
+ public static IServiceCollection AddRateLimiter(this IServiceCollection services, Action<RateLimiterOptions> configureOptions);
+ }
public static class RateLimiterOptionsExtensions
{
- public static RateLimiterOptions AddNoLimiter(this RateLimiterOptions options, string policyName)
- public static RateLimiterOptions AddTokenBucketLimiter(this RateLimiterOptions options, string policyName, TokenBucketRateLimiterOptions tokenBucketRateLimiterOptions)
+ public static RateLimiterOptions AddTokenBucketLimiter(this RateLimiterOptions options, string policyName, Action<TokenBucketRateLimiterOptions> configureOptions)
- public static RateLimiterOptions AddFixedWindowLimiter(this RateLimiterOptions options, string policyName, FixedWindowRateLimiterOptions fixedWindowRateLimiterOptions)
+ public static RateLimiterOptions AddFixedWindowLimiter(this RateLimiterOptions options, string policyName, Action< FixedWindowRateLimiterOptions> configureOptions)
- public static RateLimiterOptions AddSlidingWindowLimiter(this RateLimiterOptions options, string policyName, SlidingWindowRateLimiterOptions slidingWindowRateLimiterOptions)
+ public static RateLimiterOptions AddSlidingWindowLimiter(this RateLimiterOptions options, string policyName, Action< SlidingWindowRateLimiterOptions> configureOptions)
- public static RateLimiterOptions AddConcurrencyLimiter(this RateLimiterOptions options, string policyName, ConcurrencyLimiterOptions concurrencyLimiterOptions)
+ public static RateLimiterOptions AddConcurrencyLimiter(this RateLimiterOptions options, string policyName, Action< ConcurrencyLimiterOptions> configureOptions)
}
public static class RateLimiterEndpointConventionBuilderExtensions
{
+ public static TBuilder DisableRateLimiting<TBuilder>(this TBuilder builder) where TBuilder : IEndpointConventionBuilder
+ public static TBuilder RequireRateLimiting<TBuilder, TPartitionKey>(this TBuilder builder, IRateLimiterPolicy<TPartitionKey> policy) where TBuilder : IEndpointConventionBuilder
} |
We think that this isn't a broad enough use case to merit its addition at the moment, though we could be open to it in the future. It would also add complexity in the way we instantiate RateLimiters/Policies, since for the ones added in this way, we'd have to wait until we were in the middleware to do so. |
I'm proposing a slight change to the approved API. namespace Microsoft.AspNetCore.RateLimiting
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class EnableRateLimitingAttribute : Attribute
{
public EnableRateLimitingAttribute(string policyName);
- string PolicyName { get; }
+ string? PolicyName { get; }
} By putting an EnableRateLimitingAttribute on the endpoint with a null PolicyName, and setting an internal DefaultRateLimiterPolicy field on that EnableRateLimitingAttribute. PolicyName will only ever be null when we go through this code path – we’ll still throw if the user tries to set the PolicyName as null. Another option which I just thought of would be to not make PolicyName nullable & have RequireRateLimiting<TBuilder, TPartitionKey> set a new EnableRateLimitingAttribute with some arbitrary PolicyName like the empty string – the presence of a |
Thank you for submitting this for API review. This will be reviewed by @dotnet/aspnet-api-review at the next meeting of the ASP.NET Core API Review group. Please ensure you take a look at the API review process documentation and ensure that:
|
I think the nullability change makes sense here. Someone could easily name their policy I think we should approve this API. |
API review Notes:
API Approved! (Diff from previously approved API) namespace Microsoft.AspNetCore.RateLimiting
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class EnableRateLimitingAttribute : Attribute
{
public EnableRateLimitingAttribute(string policyName);
- string PolicyName { get; }
+ string? PolicyName { get; }
} |
NOTE - This is the original draft of the proposal. The updated proposal is at this comment: #42667 (comment)
Q's - keep
OnRejected
as aFunc
because it's nullable? Change extension methods likeAddTokenBucketLimiter
toAddTokenBucketLimiterPolicy
? Add an attribute for MVC Controllers?The text was updated successfully, but these errors were encountered: