RateLimiting: rename folder, target net10.0, own the rejection handling - #2164
Open
vladimir-pecanac-main wants to merge 1 commit into
Open
Conversation
…he rejection handling - aspnetcore-webapi/RateLimitingDotNET8 renamed to aspnetcore-webapi/RateLimiting (solution, both projects and the namespace with it) so the folder name stops contradicting its target framework. - Both projects retargeted net8.0 -> net10.0. Swashbuckle.AspNetCore 6.5.0 -> 10.2.3 (kept, not swapped: the Swagger UI is how a reader fires requests at these endpoints), Microsoft.AspNetCore.Mvc.Testing 8.0.2 -> 10.0.11, Microsoft.NET.Test.Sdk 17.6.0 -> 18.9.0, xunit 2.4.2 -> 2.9.3, xunit.runner.visualstudio 2.4.5 -> 4.0.0, coverlet.collector 6.0.0 -> 10.0.1. - RejectionHandling: one AddRateLimiter call now owns RejectionStatusCode = 429 and an OnRejected callback that writes Retry-After from MetadataName.RetryAfter. The 429 used to be set inside AuthorizationRateLimiter, where every other policy inherited it by side effect. - The class-level [EnableRateLimiting(Policies.Fixed)] on CustomerController is no longer commented out, with tests covering both it and the action-level override. - GetOptionValues reads configuration directly instead of building a throwaway service provider per limiter. - The sample's own RateLimiterOptions class renamed to LimiterSettings so it stops colliding with Microsoft.AspNetCore.RateLimiting.RateLimiterOptions. - New tests: controller policy applies, action policy overrides it, Retry-After is written, the global limiter runs alongside the endpoint limiter, and [DisableRateLimiting] beats it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Modernises the rate limiting sample and makes the article's central claim demonstrable in code.
Folder rename.
aspnetcore-webapi/RateLimitingDotNET8becomesaspnetcore-webapi/RateLimiting: the solution, both projects and the namespace go with it. The name baked in a version the sample no longer targets, and a version-free name means this never recurs. Exactly one article links this folder, so the rename is a one-article change.Retarget and packages. Both projects net8.0 to net10.0.
Swashbuckle.AspNetCoreMicrosoft.AspNetCore.Mvc.TestingMicrosoft.NET.Test.Sdkxunitxunit.runner.visualstudiocoverlet.collectorSwashbuckle is bumped rather than swapped for
Microsoft.AspNetCore.OpenApi: the Swagger UI is how a reader fires requests at the rate-limited endpoints by hand, andMapOpenApi()ships no UI to do that with. Thexunit.runner.visualstudio2.4.5 to 4.0.0 jump does not require moving toxunit.v3; 2.9.3 plus runner 4.0.0 builds and runs clean, which the test output below shows.Rejection handling gets its own registration.
RejectionStatusCode = 429used to be set insideAuthorizationRateLimiter(), and every other policy in the sample inherited it by side effect, because repeatedAddRateLimiter()calls configure the same options instance. The four documented limiters therefore appeared to return 429 while the code the article prints returns the framework default, 503. A newRateLimiters.RejectionHandling()now owns that setting and adds anOnRejectedcallback that writesRetry-AfterfromMetadataName.RetryAfter.The class-level attribute is live.
[EnableRateLimiting(Policies.Fixed)]onCustomerControllerwas commented out, so the sample could not demonstrate the article's action-overrides-controller claim. It is uncommented, with tests for both halves.Two smaller fixes.
GetOptionValues<T>built a throwaway service provider once per limiter, five times at startup; it now reads configuration directly, the wayAuthorizationRateLimiteralready did. (Note: ASP0000 is not actually raised on this shape, the build is warning-free either way; the fix stands on the five discarded providers, not on an analyzer.) And the sample's ownRateLimiterOptionsclass is renamedLimiterSettingsso it no longer collides by name withMicrosoft.AspNetCore.RateLimiting.RateLimiterOptions, which is the type this sample exists to teach.Deliberately unchanged. The
httpContext.GetTokenAsync("access_token").Resultcall in the authorization partitioner stays:GetTokenAsyncdoes scheme resolution a rawAuthorizationheader read would skip, so the two are not unconditionally equivalent and the swap is not made on reasoning alone.ChainedRateLimiteralso stays unregistered; registering it would apply a 4-requests-per-2-seconds global limit partitioned by user agent, and the test client sends a fixed user agent, so every multi-request test would fail. The stub is deliberate.New tests (5). Controller policy applies to an action without its own attribute; an action attribute overrides the controller's;
Retry-Afteris written on a token bucket rejection; the global limiter is enforced alongside the endpoint limiter rather than instead of it;[DisableRateLimiting]beats the global limiter.SDK 10.0.302, runtime 10.0.10.