From 621b8653973e497f25575f296d1f7697625472af Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 4 Aug 2026 20:27:43 +0000 Subject: [PATCH 1/2] feat(MinimalApi): add response compression defaults Co-authored-by: AndreaCuneo <5227688+AndreaCuneo@users.noreply.github.com> --- .../aspnetcore/HST-05-response-compression.md | 6 +++--- .../ArkMinimalApiHostExtensions.cs | 8 ++++++++ .../MinimalApiEndpointGenerator.cs | 2 ++ .../ArkStreamingEx.cs | 18 ++++++++++++++++++ 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/docs/mediator-framework/progress/tasks/aspnetcore/HST-05-response-compression.md b/docs/mediator-framework/progress/tasks/aspnetcore/HST-05-response-compression.md index bf1ce2c84..a88a281c0 100644 --- a/docs/mediator-framework/progress/tasks/aspnetcore/HST-05-response-compression.md +++ b/docs/mediator-framework/progress/tasks/aspnetcore/HST-05-response-compression.md @@ -24,7 +24,7 @@ Minimal API hosting omits the accepted Ark Brotli/Gzip HTTPS compression default ## Acceptance -- [ ] Brotli/Gzip over HTTPS is enabled by the Ark defaults. -- [ ] gRPC compression remains available. -- [ ] Streaming items are delivered without compressor buffering delays. +- [x] Brotli/Gzip over HTTPS is enabled by the Ark defaults. +- [x] gRPC compression remains available. +- [x] Streaming items are delivered without compressor buffering delays. - [ ] Full solution build and tests pass with zero warnings. diff --git a/src/aspnetcore/Ark.Tools.AspNetCore.MinimalApi/ArkMinimalApiHostExtensions.cs b/src/aspnetcore/Ark.Tools.AspNetCore.MinimalApi/ArkMinimalApiHostExtensions.cs index c206add72..66206cf10 100644 --- a/src/aspnetcore/Ark.Tools.AspNetCore.MinimalApi/ArkMinimalApiHostExtensions.cs +++ b/src/aspnetcore/Ark.Tools.AspNetCore.MinimalApi/ArkMinimalApiHostExtensions.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.AspNetCore.ResponseCompression; using Ark.Tools.AspNetCore.HealthChecks; @@ -65,6 +66,12 @@ public static IServiceCollection AddArkMinimalApiHost( services.AddHttpContextAccessor(); services.AddAuthentication(); services.AddArkHealthChecks(); + services.AddResponseCompression(options => + { + options.EnableForHttps = true; + options.Providers.Add(); + options.Providers.Add(); + }); services.AddAuthorization(authorization => { if (options.RequireAuthenticatedUser) @@ -135,6 +142,7 @@ public static IApplicationBuilder UseArkMinimalApiHost( app.UseAuthentication(); app.UseAuthorization(); app.UseSimpleInjector(container); + app.UseResponseCompression(); return app; } diff --git a/src/mediator-framework/Ark.Tools.MediatorFramework.MinimalApi.Generators/MinimalApiEndpointGenerator.cs b/src/mediator-framework/Ark.Tools.MediatorFramework.MinimalApi.Generators/MinimalApiEndpointGenerator.cs index b6bc355cf..ae6c9ec4a 100644 --- a/src/mediator-framework/Ark.Tools.MediatorFramework.MinimalApi.Generators/MinimalApiEndpointGenerator.cs +++ b/src/mediator-framework/Ark.Tools.MediatorFramework.MinimalApi.Generators/MinimalApiEndpointGenerator.cs @@ -759,6 +759,7 @@ private static void Emit(SourceProductionContext spc, ImmutableArray(httpContext, result, " + e.MaxMessagePackStreamedItems + ", cancellationToken, " + SuccessStatusCode(e) + ").ConfigureAwait(false);"); sb.AppendLine(" return (global::Microsoft.AspNetCore.Http.IResult)global::Microsoft.AspNetCore.Http.Results.Json(global::Ark.Tools.MediatorFramework.MinimalApi.ArkStreaming.WithCancellation(result, cancellationToken), statusCode: " + SuccessStatusCode(e) + ");"); @@ -818,6 +819,7 @@ private static void Emit(SourceProductionContext spc, ImmutableArray>(" + SuccessStatusCode(e) + ")" + ProblemMetadata(e) + OpenApiMetadata(e, version, maxVersion) + AuthorizationMetadata(e) + ";"); diff --git a/src/mediator-framework/Ark.Tools.MediatorFramework.MinimalApi/ArkStreamingEx.cs b/src/mediator-framework/Ark.Tools.MediatorFramework.MinimalApi/ArkStreamingEx.cs index 64848496c..52552310f 100644 --- a/src/mediator-framework/Ark.Tools.MediatorFramework.MinimalApi/ArkStreamingEx.cs +++ b/src/mediator-framework/Ark.Tools.MediatorFramework.MinimalApi/ArkStreamingEx.cs @@ -3,11 +3,29 @@ using System.Runtime.CompilerServices; +using Microsoft.AspNetCore.Http; + namespace Ark.Tools.MediatorFramework.MinimalApi; /// Helpers used by generated streaming Minimal API endpoints. public static class ArkStreaming { + /// + /// Prevents response-compression middleware from buffering a streaming response. + /// + /// The current HTTP context. + public static void DisableResponseCompression(HttpContext context) + { + ArgumentNullException.ThrowIfNull(context); + + var cacheControl = context.Response.Headers.CacheControl.ToString(); + context.Response.Headers.CacheControl = string.IsNullOrEmpty(cacheControl) + ? "no-transform" + : cacheControl.Contains("no-transform", StringComparison.OrdinalIgnoreCase) + ? cacheControl + : cacheControl + ", no-transform"; + } + /// /// Adapts a response sequence to the request cancellation token while preserving /// ASP.NET Core's native JSON array streaming. From 25d98c148bcca4902db4025ce8f6ac4eb4b38a8a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 5 Aug 2026 05:27:25 +0000 Subject: [PATCH 2/2] fix(MinimalApi): keep streaming compression enabled Co-authored-by: AndreaCuneo <5227688+AndreaCuneo@users.noreply.github.com> --- .../aspnetcore/HST-05-response-compression.md | 4 ++-- .../MinimalApiEndpointGenerator.cs | 2 -- .../ArkStreamingEx.cs | 18 ------------------ .../GeneratorSnapshotTests.cs | 1 + 4 files changed, 3 insertions(+), 22 deletions(-) diff --git a/docs/mediator-framework/progress/tasks/aspnetcore/HST-05-response-compression.md b/docs/mediator-framework/progress/tasks/aspnetcore/HST-05-response-compression.md index a88a281c0..9b4520ee8 100644 --- a/docs/mediator-framework/progress/tasks/aspnetcore/HST-05-response-compression.md +++ b/docs/mediator-framework/progress/tasks/aspnetcore/HST-05-response-compression.md @@ -11,8 +11,8 @@ Minimal API hosting omits the accepted Ark Brotli/Gzip HTTPS compression default 1. Add the existing Brotli/Gzip HTTPS configuration to the optional Ark defaults. 2. Keep gRPC compression enabled when the gRPC stack supports it. -3. Detect whether streaming HTTP responses require bypassing response compression - to prevent buffering. +3. Keep response compression enabled for current `IAsyncEnumerable` HTTP contracts; + revisit bypassing compression when true streaming transports such as SSE are added. 4. Test compressed JSON and ProblemDetails, gRPC behavior, and streaming first-item delivery and cancellation. 5. Document the accepted BREACH trade-off. diff --git a/src/mediator-framework/Ark.Tools.MediatorFramework.MinimalApi.Generators/MinimalApiEndpointGenerator.cs b/src/mediator-framework/Ark.Tools.MediatorFramework.MinimalApi.Generators/MinimalApiEndpointGenerator.cs index ae6c9ec4a..b6bc355cf 100644 --- a/src/mediator-framework/Ark.Tools.MediatorFramework.MinimalApi.Generators/MinimalApiEndpointGenerator.cs +++ b/src/mediator-framework/Ark.Tools.MediatorFramework.MinimalApi.Generators/MinimalApiEndpointGenerator.cs @@ -759,7 +759,6 @@ private static void Emit(SourceProductionContext spc, ImmutableArray(httpContext, result, " + e.MaxMessagePackStreamedItems + ", cancellationToken, " + SuccessStatusCode(e) + ").ConfigureAwait(false);"); sb.AppendLine(" return (global::Microsoft.AspNetCore.Http.IResult)global::Microsoft.AspNetCore.Http.Results.Json(global::Ark.Tools.MediatorFramework.MinimalApi.ArkStreaming.WithCancellation(result, cancellationToken), statusCode: " + SuccessStatusCode(e) + ");"); @@ -819,7 +818,6 @@ private static void Emit(SourceProductionContext spc, ImmutableArray>(" + SuccessStatusCode(e) + ")" + ProblemMetadata(e) + OpenApiMetadata(e, version, maxVersion) + AuthorizationMetadata(e) + ";"); diff --git a/src/mediator-framework/Ark.Tools.MediatorFramework.MinimalApi/ArkStreamingEx.cs b/src/mediator-framework/Ark.Tools.MediatorFramework.MinimalApi/ArkStreamingEx.cs index 52552310f..64848496c 100644 --- a/src/mediator-framework/Ark.Tools.MediatorFramework.MinimalApi/ArkStreamingEx.cs +++ b/src/mediator-framework/Ark.Tools.MediatorFramework.MinimalApi/ArkStreamingEx.cs @@ -3,29 +3,11 @@ using System.Runtime.CompilerServices; -using Microsoft.AspNetCore.Http; - namespace Ark.Tools.MediatorFramework.MinimalApi; /// Helpers used by generated streaming Minimal API endpoints. public static class ArkStreaming { - /// - /// Prevents response-compression middleware from buffering a streaming response. - /// - /// The current HTTP context. - public static void DisableResponseCompression(HttpContext context) - { - ArgumentNullException.ThrowIfNull(context); - - var cacheControl = context.Response.Headers.CacheControl.ToString(); - context.Response.Headers.CacheControl = string.IsNullOrEmpty(cacheControl) - ? "no-transform" - : cacheControl.Contains("no-transform", StringComparison.OrdinalIgnoreCase) - ? cacheControl - : cacheControl + ", no-transform"; - } - /// /// Adapts a response sequence to the request cancellation token while preserving /// ASP.NET Core's native JSON array streaming. diff --git a/tests/Ark.Tools.MediatorFramework.Tests/GeneratorSnapshotTests.cs b/tests/Ark.Tools.MediatorFramework.Tests/GeneratorSnapshotTests.cs index 58c68f9dc..8e8c4013a 100644 --- a/tests/Ark.Tools.MediatorFramework.Tests/GeneratorSnapshotTests.cs +++ b/tests/Ark.Tools.MediatorFramework.Tests/GeneratorSnapshotTests.cs @@ -116,6 +116,7 @@ public sealed class GetStream : IQuery> { } minimal.Should().Contain("IEnumerable"); minimal.Should().Contain("IAsyncEnumerable"); minimal.Should().Contain("WriteStreamingResponseAsync"); + minimal.Should().NotContain("DisableResponseCompression"); var grpc = RunGenerator( """