From 87c8891409ece3d87aaabba86f1214eb6454239a Mon Sep 17 00:00:00 2001 From: Mitch Denny Date: Fri, 24 Mar 2023 17:09:18 +1100 Subject: [PATCH 1/4] Support populating cache without serving from it. --- src/Middleware/OutputCaching/src/OutputCacheMiddleware.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Middleware/OutputCaching/src/OutputCacheMiddleware.cs b/src/Middleware/OutputCaching/src/OutputCacheMiddleware.cs index 0fb2d123ca20..76b0bdb75e2d 100644 --- a/src/Middleware/OutputCaching/src/OutputCacheMiddleware.cs +++ b/src/Middleware/OutputCaching/src/OutputCacheMiddleware.cs @@ -119,6 +119,8 @@ private async Task InvokeAwaited(HttpContext httpContext, IReadOnlyList Date: Mon, 27 Mar 2023 11:28:06 +1100 Subject: [PATCH 2/4] Add test case for scenario. --- .../test/OutputCacheMiddlewareTests.cs | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs b/src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs index 4b6088ac121f..6836a546a0fc 100644 --- a/src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs +++ b/src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs @@ -962,4 +962,74 @@ public async Task EmptyCacheKey_IsNotCached() sink.Writes, LoggedMessage.ResponseCached); } + + public class RefreshableCachePolicy : IOutputCachePolicy + { + public ValueTask CacheRequestAsync(OutputCacheContext context, CancellationToken cancellation) + { + context.AllowCacheLookup = !context.HttpContext.Request.Headers.ContainsKey("X-Refresh"); + context.AllowCacheStorage = true; + return ValueTask.CompletedTask; + } + + public ValueTask ServeFromCacheAsync(OutputCacheContext context, CancellationToken cancellation) + { + return ValueTask.CompletedTask; + } + + public ValueTask ServeResponseAsync(OutputCacheContext context, CancellationToken cancellation) + { + return ValueTask.CompletedTask; + } + } + + + + [Fact] + public async Task Can_Implement_Policy_That_Enables_Storage_Without_Serving() + { + var options = new OutputCacheOptions(); + options.AddBasePolicy(builder => + { + builder.AddPolicy(new RefreshableCachePolicy()); + builder.Cache(); + }, true); + + var cache = new TestOutputCache(); + var sink = new TestSink(); + var middleware = TestUtils.CreateTestMiddleware(options: options, testSink: sink, cache: cache, next: async c => + { + await c.Response.WriteAsync(Guid.NewGuid().ToString()); + }); + + // Act - what I'm doing here is making four requests. The third request + // should trigger a cache refresh so that the first two requests + // have matching output, and the last two have matching output. + var initialResponse = await SendRequestAsync(includeRefreshHeader: false); + var cachedResponse = await SendRequestAsync(includeRefreshHeader: false); + var refreshedResponse = await SendRequestAsync(includeRefreshHeader: true); + var cachedResponseAfterRefresh = await SendRequestAsync(includeRefreshHeader: false); + + Assert.Equal(initialResponse, cachedResponse); + Assert.NotEqual(cachedResponse, refreshedResponse); + Assert.Equal(refreshedResponse, cachedResponseAfterRefresh); + + async Task SendRequestAsync(bool includeRefreshHeader) + { + var requestContext = TestUtils.CreateTestContext(cache: cache); + requestContext.HttpContext.Request.Method = "GET"; + requestContext.HttpContext.Request.Path = "/"; + var responseStream = new MemoryStream(); + requestContext.HttpContext.Response.Body = responseStream; + + if (includeRefreshHeader) + { + requestContext.HttpContext.Request.Headers.Add("X-Refresh", "randomvalue"); + } + + await middleware.Invoke(requestContext.HttpContext); + var response = Encoding.UTF8.GetString(responseStream.GetBuffer()); + return response; + } + } } From b7029e1b0b025249b1692c862e8de9a3b039a6c1 Mon Sep 17 00:00:00 2001 From: Mitch Denny Date: Mon, 27 Mar 2023 12:23:25 +1100 Subject: [PATCH 3/4] Fix whitespace. --- src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs b/src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs index 6836a546a0fc..ee2f870dad4e 100644 --- a/src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs +++ b/src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs @@ -983,8 +983,6 @@ public ValueTask ServeResponseAsync(OutputCacheContext context, CancellationToke } } - - [Fact] public async Task Can_Implement_Policy_That_Enables_Storage_Without_Serving() { From ff7db115a4458a45b956d36ff5bd04195b7696a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Ros?= Date: Mon, 27 Mar 2023 10:43:58 -0700 Subject: [PATCH 4/4] Update OutputCacheMiddlewareTests.cs --- src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs b/src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs index ee2f870dad4e..8b01426edf98 100644 --- a/src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs +++ b/src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs @@ -1000,7 +1000,7 @@ public async Task Can_Implement_Policy_That_Enables_Storage_Without_Serving() await c.Response.WriteAsync(Guid.NewGuid().ToString()); }); - // Act - what I'm doing here is making four requests. The third request + // Act - Four requests are executed. The third request // should trigger a cache refresh so that the first two requests // have matching output, and the last two have matching output. var initialResponse = await SendRequestAsync(includeRefreshHeader: false);