Skip to content

Add System.Web (classic ASP.NET) integration: async IHttpModule#3

Merged
renansj merged 2 commits into
mainfrom
feat/systemweb-integration
Jun 2, 2026
Merged

Add System.Web (classic ASP.NET) integration: async IHttpModule#3
renansj merged 2 commits into
mainfrom
feat/systemweb-integration

Conversation

@renansj

@renansj renansj commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Summary

Additive integration so AppRateLimiter works in classic System.Web apps (WebForms / MVC 5 / Web API 2), the common IIS web-farm-behind-a-load-balancer scenario. Reuses the existing store and rules; the Redis store already makes the counter global.

What changed (additive only)

  • New project src/AppRateLimiter.Web (net472), packaged as AppRateLimiter.Web:
    • RateLimitHttpModule: async IHttpModule. IP rules on BeginRequest (pre-auth), claim rules on PostAuthenticateRequest (post-auth, from the validated HttpContext.User). Awaits HitAsync via EventHandlerTaskAsyncHelper (no blocking). On exceed: 429 + Retry-After + the same JSON body as the ASP.NET Core middleware, then CompleteRequest.
    • Static Configure(store, ipRules, claimRules) entry point for Global.asax (classic modules can't use DI).
    • WebRateLimitRules.ByIp/ByClaim over HttpContextBase: IP from UserHostAddress, XFF only behind configured trusted proxies (right-to-left, skip trusted), IPv6 to /64; ByClaim only when authenticated, value via ClaimsPrincipal.FindFirst.
  • Core (netstandard2.0, no behavior change): exposed IpAddressResolver.NormalizeIp(IPAddress) and RateLimitMiddleware.KeySeparator publicly so the adapter builds byte-identical keys. Existing public members unchanged.
  • Web API 2 DelegatingHandler (optional item) intentionally skipped: the IHttpModule already covers Web API 2 at the pipeline level, and a handler would add System.Web.Http deps for marginal value.

Backward compatibility

  • AppRateLimiter and AppRateLimiter.Redis stay netstandard2.0. No existing public type/signature/behavior changed. Existing tests untouched.

Tests

  • New net472 tests (tests/AppRateLimiter.Web.Tests, Moq): ByIp/ByClaim selector parity, IPv6 /64 collapse, XFF only-behind-trusted-proxy, default rule names, and a module behavior test that rejects after the limit (429 + Retry-After + JSON body) using InMemoryRateLimitStore + a faked HttpContextBase. Run on a windows-latest CI job (net472 needs the real Framework runtime; Linux would need mono).
  • IP normalization parity test added to the net10 integration project (runs in the Linux job).

CI

  • Linux job now builds the whole solution (net472 builds via Microsoft.NETFramework.ReferenceAssemblies) and packs AppRateLimiter.Web too.
  • New windows-latest job runs the net472 Web tests.
  • Sample.NetFramework now builds in CI (reference assemblies added).

Local verification (this box has only .NET SDK 6, so net10 tests run in CI)

  • dotnet build of the core (netstandard2.0): 0 warnings, 0 errors.
  • dotnet build of AppRateLimiter.Web (net472) on Linux: 0 warnings, 0 errors; nupkg includes README, MIT license, deps on AppRateLimiter 1.0.0 + AppRateLimiter.Redis 1.0.1, System.Web as framework assembly, no leaked ReferenceAssemblies dep.

Full test suite (in-memory, Redis store-level, multi-pod, and the new Web tests) is verified by CI.

renansj added 2 commits June 2, 2026 15:30
…tpModule

Additive net472 package AppRateLimiter.Web with RateLimitHttpModule (async,
EventHandlerTaskAsyncHelper), WebRateLimitRules ByIp/ByClaim over HttpContextBase,
reusing the core store and rules. Exposes IpAddressResolver.NormalizeIp and
RateLimitMiddleware.KeySeparator publicly (additive) for parity. Core and Redis stay
netstandard2.0 and unchanged behaviorally. Adds Windows CI job for net472 tests.
@renansj renansj merged commit 945cd85 into main Jun 2, 2026
2 checks passed
@renansj renansj deleted the feat/systemweb-integration branch June 2, 2026 19:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant