From c4af242052739b216ed9dc43cc862e4ecec49114 Mon Sep 17 00:00:00 2001 From: Elfocrash Date: Thu, 12 May 2022 12:21:05 +0100 Subject: [PATCH 1/6] Changed the Rate Limiter API to action-based --- .../RateLimiting/src/PublicAPI.Unshipped.txt | 2 +- .../src/RateLimitingApplicationBuilderExtensions.cs | 7 +++++-- .../RateLimitingApplicationBuilderExtensionsTests.cs | 10 ++++++---- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/Middleware/RateLimiting/src/PublicAPI.Unshipped.txt b/src/Middleware/RateLimiting/src/PublicAPI.Unshipped.txt index b62cec89b1cc..517e642275a0 100644 --- a/src/Middleware/RateLimiting/src/PublicAPI.Unshipped.txt +++ b/src/Middleware/RateLimiting/src/PublicAPI.Unshipped.txt @@ -8,4 +8,4 @@ Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.OnRejected.set -> void Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.RateLimiterOptions() -> void Microsoft.AspNetCore.RateLimiting.RateLimitingApplicationBuilderExtensions static Microsoft.AspNetCore.RateLimiting.RateLimitingApplicationBuilderExtensions.UseRateLimiter(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app) -> Microsoft.AspNetCore.Builder.IApplicationBuilder! -static Microsoft.AspNetCore.RateLimiting.RateLimitingApplicationBuilderExtensions.UseRateLimiter(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app, Microsoft.AspNetCore.RateLimiting.RateLimiterOptions! options) -> Microsoft.AspNetCore.Builder.IApplicationBuilder! +static Microsoft.AspNetCore.RateLimiting.RateLimitingApplicationBuilderExtensions.UseRateLimiter(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app, System.Action options) -> Microsoft.AspNetCore.Builder.IApplicationBuilder! diff --git a/src/Middleware/RateLimiting/src/RateLimitingApplicationBuilderExtensions.cs b/src/Middleware/RateLimiting/src/RateLimitingApplicationBuilderExtensions.cs index 7cda2ab98c53..5953d9d95635 100644 --- a/src/Middleware/RateLimiting/src/RateLimitingApplicationBuilderExtensions.cs +++ b/src/Middleware/RateLimiting/src/RateLimitingApplicationBuilderExtensions.cs @@ -29,11 +29,14 @@ public static IApplicationBuilder UseRateLimiter(this IApplicationBuilder app) /// /// /// - public static IApplicationBuilder UseRateLimiter(this IApplicationBuilder app, RateLimiterOptions options) + public static IApplicationBuilder UseRateLimiter(this IApplicationBuilder app, Action options) { ArgumentNullException.ThrowIfNull(app, nameof(app)); ArgumentNullException.ThrowIfNull(options, nameof(options)); - return app.UseMiddleware(Options.Create(options)); + var rateLimiterOptions = new RateLimiterOptions(); + options?.Invoke(rateLimiterOptions); + + return app.UseMiddleware(Options.Create(rateLimiterOptions)); } } diff --git a/src/Middleware/RateLimiting/test/RateLimitingApplicationBuilderExtensionsTests.cs b/src/Middleware/RateLimiting/test/RateLimitingApplicationBuilderExtensionsTests.cs index 37d6d5bc4c37..b32f06d606a5 100644 --- a/src/Middleware/RateLimiting/test/RateLimitingApplicationBuilderExtensionsTests.cs +++ b/src/Middleware/RateLimiting/test/RateLimitingApplicationBuilderExtensionsTests.cs @@ -28,9 +28,11 @@ public void UseRateLimiter_ThrowsOnNullOptions() public void UseRateLimiter_RespectsOptions() { // These are the options that should get used - var options = new RateLimiterOptions(); - options.DefaultRejectionStatusCode = 429; - options.Limiter = new TestPartitionedRateLimiter(new TestRateLimiter(false)); + var configureOptions = new Action(opt => + { + opt.DefaultRejectionStatusCode = 429; + opt.Limiter = new TestPartitionedRateLimiter(new TestRateLimiter(false)); + }); // These should not get used var services = new ServiceCollection(); @@ -44,7 +46,7 @@ public void UseRateLimiter_RespectsOptions() var appBuilder = new ApplicationBuilder(serviceProvider); // Act - appBuilder.UseRateLimiter(options); + appBuilder.UseRateLimiter(configureOptions); var app = appBuilder.Build(); var context = new DefaultHttpContext(); app.Invoke(context); From 596ce37f0bb2b4f0d350f57fbb9b43997ec5b171 Mon Sep 17 00:00:00 2001 From: Elfocrash Date: Thu, 12 May 2022 12:33:47 +0100 Subject: [PATCH 2/6] Fixes the API --- src/Middleware/RateLimiting/src/PublicAPI.Unshipped.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Middleware/RateLimiting/src/PublicAPI.Unshipped.txt b/src/Middleware/RateLimiting/src/PublicAPI.Unshipped.txt index 517e642275a0..01e163b51c90 100644 --- a/src/Middleware/RateLimiting/src/PublicAPI.Unshipped.txt +++ b/src/Middleware/RateLimiting/src/PublicAPI.Unshipped.txt @@ -8,4 +8,4 @@ Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.OnRejected.set -> void Microsoft.AspNetCore.RateLimiting.RateLimiterOptions.RateLimiterOptions() -> void Microsoft.AspNetCore.RateLimiting.RateLimitingApplicationBuilderExtensions static Microsoft.AspNetCore.RateLimiting.RateLimitingApplicationBuilderExtensions.UseRateLimiter(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app) -> Microsoft.AspNetCore.Builder.IApplicationBuilder! -static Microsoft.AspNetCore.RateLimiting.RateLimitingApplicationBuilderExtensions.UseRateLimiter(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app, System.Action options) -> Microsoft.AspNetCore.Builder.IApplicationBuilder! +static Microsoft.AspNetCore.RateLimiting.RateLimitingApplicationBuilderExtensions.UseRateLimiter(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app, System.Action! options) -> Microsoft.AspNetCore.Builder.IApplicationBuilder! From 43767b2f19fbbd1b5270f8c2055e24e9e696ea62 Mon Sep 17 00:00:00 2001 From: Nick Chapsas Date: Thu, 12 May 2022 14:01:44 +0100 Subject: [PATCH 3/6] Removed the unnecessary null check Co-authored-by: Weihan Li --- .../src/RateLimitingApplicationBuilderExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Middleware/RateLimiting/src/RateLimitingApplicationBuilderExtensions.cs b/src/Middleware/RateLimiting/src/RateLimitingApplicationBuilderExtensions.cs index 5953d9d95635..305d38634f7c 100644 --- a/src/Middleware/RateLimiting/src/RateLimitingApplicationBuilderExtensions.cs +++ b/src/Middleware/RateLimiting/src/RateLimitingApplicationBuilderExtensions.cs @@ -35,7 +35,7 @@ public static IApplicationBuilder UseRateLimiter(this IApplicationBuilder app, A ArgumentNullException.ThrowIfNull(options, nameof(options)); var rateLimiterOptions = new RateLimiterOptions(); - options?.Invoke(rateLimiterOptions); + options.Invoke(rateLimiterOptions); return app.UseMiddleware(Options.Create(rateLimiterOptions)); } From 00fda6f2d037fbc8872686ddb579790e794a7b23 Mon Sep 17 00:00:00 2001 From: "Md.Rubel" Date: Sun, 2 Aug 2026 07:38:56 +0600 Subject: [PATCH 4/6] Register AddProjectCommand in OpenAPI tool Complete the OpenAPI dotnet-openapi tool by registering the AddProjectCommand that was previously implemented but not wired up. This enables users to add OpenAPI references from project files. --- src/Tools/Microsoft.dotnet-openapi/src/Commands/AddCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tools/Microsoft.dotnet-openapi/src/Commands/AddCommand.cs b/src/Tools/Microsoft.dotnet-openapi/src/Commands/AddCommand.cs index e4066cdf2e83..5b814ed9ee68 100644 --- a/src/Tools/Microsoft.dotnet-openapi/src/Commands/AddCommand.cs +++ b/src/Tools/Microsoft.dotnet-openapi/src/Commands/AddCommand.cs @@ -14,7 +14,7 @@ public AddCommand(Application parent, IHttpClientWrapper httpClient) : base(parent, CommandName, httpClient) { Commands.Add(new AddFileCommand(this, httpClient)); - //TODO: Add AddprojectComand here: https://github.com/dotnet/aspnetcore/issues/12738 + Commands.Add(new AddProjectCommand(this, httpClient)); Commands.Add(new AddURLCommand(this, httpClient)); } From ccfebca6ba7bee5fc67c0c3b3b4d506dd42147cd Mon Sep 17 00:00:00 2001 From: "Md.Rubel" Date: Sun, 2 Aug 2026 07:40:05 +0600 Subject: [PATCH 5/6] Replace Uri.UnescapeDataString with UrlDecoder in FormReader Use the more accurate UrlDecoder for URL form data decoding instead of Uri.UnescapeDataString which has known limitations with UTF-8 sequences and cross-platform behavior differences. --- src/Http/WebUtilities/src/FormReader.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Http/WebUtilities/src/FormReader.cs b/src/Http/WebUtilities/src/FormReader.cs index e0875c97da3b..fba555cb4b2e 100644 --- a/src/Http/WebUtilities/src/FormReader.cs +++ b/src/Http/WebUtilities/src/FormReader.cs @@ -4,6 +4,7 @@ using System.Buffers; using System.Diagnostics.CodeAnalysis; using System.Text; +using Microsoft.AspNetCore.Internal; using Microsoft.Extensions.Primitives; namespace Microsoft.AspNetCore.WebUtilities; @@ -264,10 +265,12 @@ private bool ReadChar(char separator, int limit, [NotNullWhen(true)] out string? // '+' un-escapes to ' ', %HH un-escapes as ASCII (or utf-8?) private string BuildWord() { - _builder.Replace('+', ' '); var result = _builder.ToString(); _builder.Clear(); - return Uri.UnescapeDataString(result); // TODO: Replace this, it's not completely accurate. + + var bytes = Encoding.UTF8.GetBytes(result); + var decodedLength = UrlDecoder.DecodeInPlace(bytes, isFormEncoding: true); + return Encoding.UTF8.GetString(bytes, 0, decodedLength); } private void Buffer() From fdbb9845519a659d50223f97bb234c2e91fd32ea Mon Sep 17 00:00:00 2001 From: "Md.Rubel" Date: Sun, 2 Aug 2026 07:40:55 +0600 Subject: [PATCH 6/6] Add Redis connection error handling in GetAndRefresh Implement error handling for Redis operations in the GetAndRefresh method by wrapping hash member get operations in try-catch to handle Redis connection failures gracefully. This addresses the TODO for error handling in cache retrieval operations. Co-Authored-By: Claude Haiku 4.5 --- .../StackExchangeRedis/src/RedisCache.cs | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/Caching/StackExchangeRedis/src/RedisCache.cs b/src/Caching/StackExchangeRedis/src/RedisCache.cs index 66dd4fadaff6..b66937dc766f 100644 --- a/src/Caching/StackExchangeRedis/src/RedisCache.cs +++ b/src/Caching/StackExchangeRedis/src/RedisCache.cs @@ -323,29 +323,35 @@ private void TryRegisterProfiler() // This also resets the LRU status as desired. // TODO: Can this be done in one operation on the server side? Probably, the trick would just be the DateTimeOffset math. - RedisValue[] results; - if (getData) - { - results = _cache.HashMemberGet(_instance + key, AbsoluteExpirationKey, SlidingExpirationKey, DataKey); - } - else + try { - results = _cache.HashMemberGet(_instance + key, AbsoluteExpirationKey, SlidingExpirationKey); - } + RedisValue[] results; + if (getData) + { + results = _cache.HashMemberGet(_instance + key, AbsoluteExpirationKey, SlidingExpirationKey, DataKey); + } + else + { + results = _cache.HashMemberGet(_instance + key, AbsoluteExpirationKey, SlidingExpirationKey); + } - // TODO: Error handling - if (results.Length >= 2) - { - MapMetadata(results, out DateTimeOffset? absExpr, out TimeSpan? sldExpr); - Refresh(_cache, key, absExpr, sldExpr); - } + if (results.Length >= 2) + { + MapMetadata(results, out DateTimeOffset? absExpr, out TimeSpan? sldExpr); + Refresh(_cache, key, absExpr, sldExpr); + } - if (results.Length >= 3 && results[2].HasValue) + if (results.Length >= 3 && results[2].HasValue) + { + return results[2]; + } + + return null; + } + catch (RedisConnectionException ex) { - return results[2]; + throw new InvalidOperationException("Redis cache connection failed. See inner exception for details.", ex); } - - return null; } private async Task GetAndRefreshAsync(string key, bool getData, CancellationToken token = default(CancellationToken))