Skip to content

API additions for RateLimitingMiddleware #42667

Closed
@wtgodbe

Description

@wtgodbe

NOTE - This is the original draft of the proposal. The updated proposal is at this comment: #42667 (comment)

namespace Microsoft.AspNetCore.RateLimiting

+    public interface IRateLimiterMetadata
+    {
+    }

+    public interface IRequireRateLimiterMetadata : IRateLimiterMetadata
+    {
+        string PolicyName { get; }
+    }

+    public class RequireRateLimiterMetadata : IRequireRateLimiterMetadata 
+    {
+        public RequireRateLimiterMetadata (string policyName)
+        public string PolicyName { get; }
+    }

+    public interface IDisableRateLimiterMetadata : IRateLimiterMetadata
+    {
+    }

+    public class DisableRateLimiterMetadata : IDisableRateLimiterMetadata 
+    {
+        public RequireRateLimiterMetadata ()
+    }

    public interface IRateLimiterPolicy<TPartitionKey>
    {
-        Func<OnRejectedContext, CancellationToken, ValueTask>? OnRejected { get; }
+        ValueTask OnRejected(OnRejectedContext onRejectedContext, CancellationToken cancellationToken)
    }

namespace Microsoft.AspNetCore.Builder

   public static class RateLimiterApplicationBuilderExtensions
    {
        public static IApplicationBuilder UseRateLimiter(this IApplicationBuilder app)
-       public static IApplicationBuilder UseRateLimiter(this IApplicationBuilder app, RateLimiterOptions options)
    }

+   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 class RateLimiterEndpointConventionBuilderExtensions
    {
+        public static TBuilder DisableRateLimiting<TBuilder>(this TBuilder builder) where TBuilder : IEndpointConventionBuilder
    }

Q's - keep OnRejected as a Func because it's nullable? Change extension methods like AddTokenBucketLimiter to AddTokenBucketLimiterPolicy? Add an attribute for MVC Controllers?

Activity

added
api-suggestionEarly API idea and discussion, it is NOT ready for implementation
on Jul 11, 2022
BrennanConroy

BrennanConroy commented on Jul 11, 2022

@BrennanConroy
Member

I like the idea of skipping the middleware suggested in #41667 (comment)

added this to the 7.0-preview7 milestone on Jul 11, 2022
added
api-ready-for-reviewAPI is ready for formal API review - https://github.com/dotnet/apireviews
and removed
api-suggestionEarly API idea and discussion, it is NOT ready for implementation
on Jul 11, 2022
ghost

ghost commented on Jul 11, 2022

@ghost

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:

  • The PR contains changes to the reference-assembly that describe the API change. Or, you have included a snippet of reference-assembly-style code that illustrates the API change.
  • The PR describes the impact to users, both positive (useful new APIs) and negative (breaking changes).
  • Someone is assigned to "champion" this change in the meeting, and they understand the impact and design of the change.
halter73

halter73 commented on Jul 14, 2022

@halter73
Member

Meeting notes:

  • Let's get rid of the IRateLimiterMetadata inheritance hiearcy.

    • Rename IRequireRateLimiterMetadata to IRateLimiterMetadata. And RequireRateLimiterMetadata to RateLimiterMetadata.
    • IDisableRateLimiterMetadata stays the same name.
  • Should we allow policies defined inline?

    • It seems straightforward enough to implement well with the little time we have and it would be convenient.
  • UseRateLimiter(this IApplicationBuilder app, RateLimiterOptions options) should stay. We should still add AddRateLimiter. This is the same pattern as AddWebSockets.

  • Let's keep Func<OnRejectedContext, CancellationToken, ValueTask>? OnRejected { get; } so we know whether or not to call the global OnRejected callback. If we make it a normal method instead, we'd have to be okay with okay with always running the global OnRejected first.

  • Let's add attributes!

    • How about [RateLimit("MyPolicy")]?
    • Anything else?
      • Not at the moment. In the future (post .NET 7), it might be nice to specify rate limiting options directly via endpoint metadata though.
  • Let's put everything in the ASP.NET Core shared framework. We'll have to include System.Threading.RateLimiting in the ASP.NET Core shared framework similar to System.IO.Pipelines.

  • One last curveball from @DamianEdwards: Why can't I configure the rate limiter options (e.g. TokenBucketRateLimiterOptions) with a callback like every other "option" type?

    • The properties are read-only. You need to use the constructor.
    • Let's fix that and add setters and a default ctor to all the options types. It will have to go through runtime API review.
    • We'll also have to update methods like AddTokenBucketLimiter to take an Action<TokenBucketRateLimiterOptions> instead of TokenBucketRateLimiterOptions directly.
davidfowl

davidfowl commented on Jul 15, 2022

@davidfowl
Member

This looks great so far 😄

Kahbazi

Kahbazi commented on Jul 15, 2022

@Kahbazi
Member

IDisableRateLimiterMetadata stays the same name.

How about this one:

+    public interface IDisableRateLimiterMetadata
+    {
+        bool IsDisabled { get; }
+    }

This is according to the Guidelines and can be overriden if necessary.

How about [RateLimit("MyPolicy")]?

Also [DisableRateLimit]?

We'll also have to update methods like AddTokenBucketLimiter to take an Action instead of TokenBucketRateLimiterOptions directly.

Can it be Action<TokenBucketRateLimiterOptions, HttpContext>? This way the options could be based on the custom metadata on an endpoint.

davidfowl

davidfowl commented on Jul 15, 2022

@davidfowl
Member

Agree with @Kahbazi on the disable attribute. We need attributes for anything we have methods for.

DamianEdwards

DamianEdwards commented on Jul 15, 2022

@DamianEdwards
Member

Why does the IDisableRateLimiterMetadata need a property at all? Shouldn't it simply be a marker, like IAllowAnonymous?

18 remaining items

added
api-approvedAPI was approved in API review, it can be implemented
on Aug 1, 2022
wtgodbe

wtgodbe commented on Aug 1, 2022

@wtgodbe
MemberAuthor

Also I think it's useful to have an overload with HttpContext as well. It could be used to set the rate limiter options based on the current endpoint.

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.

wtgodbe

wtgodbe commented on Aug 9, 2022

@wtgodbe
MemberAuthor

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 DefaultRateLimiterPolicy on the EnableRateLimitingAttribute should be sufficient to tell the middleware that the attribute came thru this code path, and to just ignore the PolicyName.

added
api-ready-for-reviewAPI is ready for formal API review - https://github.com/dotnet/apireviews
and removed
api-approvedAPI was approved in API review, it can be implemented
on Aug 9, 2022
ghost

ghost commented on Aug 9, 2022

@ghost

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:

  • The PR contains changes to the reference-assembly that describe the API change. Or, you have included a snippet of reference-assembly-style code that illustrates the API change.
  • The PR describes the impact to users, both positive (useful new APIs) and negative (breaking changes).
  • Someone is assigned to "champion" this change in the meeting, and they understand the impact and design of the change.
halter73

halter73 commented on Aug 9, 2022

@halter73
Member

I think the nullability change makes sense here. Someone could easily name their policy "DefaultRateLimiterPolicy", and now there might be some confusion about what policy that actually means. We could just a more obscure name and prevent anyone from adding a conflicting policy name, but I prefer making it clear that a policy can be unnamed.

I think we should approve this API.

halter73

halter73 commented on Aug 10, 2022

@halter73
Member

API review Notes:

  • We prefer nullability over a well-known name because it makes it clearer these polices haven't been given a real name.
  • We don't need to change the constructor because we need the extension method to add an inline policy. This is not supported directly with the attribute.

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; }
 }
added
api-approvedAPI was approved in API review, it can be implemented
and removed
api-ready-for-reviewAPI is ready for formal API review - https://github.com/dotnet/apireviews
on Aug 10, 2022
ghost locked as resolved and limited conversation to collaborators on Sep 14, 2022
added
area-networkingIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions
and removed on Aug 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

api-approvedAPI was approved in API review, it can be implementedarea-networkingIncludes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions

Type

No type

Projects

No projects

Relationships

None yet

    Development

    Participants

    @halter73@davidfowl@adityamandaleeka@DamianEdwards@BrennanConroy

    Issue actions

      API additions for RateLimitingMiddleware · Issue #42667 · dotnet/aspnetcore