Skip to content
This repository was archived by the owner on Nov 22, 2018. It is now read-only.

Commit 7d0097b

Browse files
committed
Add IResponseCachingFeature when middleware no-ops
1 parent cb3fc4e commit 7d0097b

File tree

3 files changed

+78
-13
lines changed

3 files changed

+78
-13
lines changed

src/Microsoft.AspNetCore.ResponseCaching/ResponseCachingMiddleware.cs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,17 @@ public async Task Invoke(HttpContext httpContext)
106106
}
107107
else
108108
{
109-
await _next(httpContext);
109+
// Add IResponseCachingFeature which may be required when the response is generated
110+
AddResponseCachingFeature(httpContext);
111+
112+
try
113+
{
114+
await _next(httpContext);
115+
}
116+
finally
117+
{
118+
RemoveResponseCachingFeature(httpContext);
119+
}
110120
}
111121
}
112122

@@ -318,6 +328,15 @@ internal Task OnResponseStartingAsync(ResponseCachingContext context)
318328
}
319329
}
320330

331+
internal static void AddResponseCachingFeature(HttpContext context)
332+
{
333+
if (context.Features.Get<IResponseCachingFeature>() != null)
334+
{
335+
throw new InvalidOperationException($"Another instance of {nameof(IResponseCachingFeature)} already exists. Only one instance of {nameof(ResponseCachingMiddleware)} can be configured for an application.");
336+
}
337+
context.Features.Set<IResponseCachingFeature>(new ResponseCachingFeature());
338+
}
339+
321340
internal void ShimResponseStream(ResponseCachingContext context)
322341
{
323342
// Shim response stream
@@ -332,14 +351,12 @@ internal void ShimResponseStream(ResponseCachingContext context)
332351
context.HttpContext.Features.Set<IHttpSendFileFeature>(new SendFileFeatureWrapper(context.OriginalSendFileFeature, context.ResponseCachingStream));
333352
}
334353

335-
// Add IResponseCachingFeature
336-
if (context.HttpContext.Features.Get<IResponseCachingFeature>() != null)
337-
{
338-
throw new InvalidOperationException($"Another instance of {nameof(ResponseCachingFeature)} already exists. Only one instance of {nameof(ResponseCachingMiddleware)} can be configured for an application.");
339-
}
340-
context.HttpContext.Features.Set<IResponseCachingFeature>(new ResponseCachingFeature());
354+
AddResponseCachingFeature(context.HttpContext);
341355
}
342356

357+
internal static void RemoveResponseCachingFeature(HttpContext context)
358+
=> context.Features.Set<IResponseCachingFeature>(null);
359+
343360
internal static void UnshimResponseStream(ResponseCachingContext context)
344361
{
345362
// Unshim response stream
@@ -349,7 +366,7 @@ internal static void UnshimResponseStream(ResponseCachingContext context)
349366
context.HttpContext.Features.Set(context.OriginalSendFileFeature);
350367

351368
// Remove IResponseCachingFeature
352-
context.HttpContext.Features.Set<IResponseCachingFeature>(null);
369+
RemoveResponseCachingFeature(context.HttpContext);
353370
}
354371

355372
internal static bool ContentIsNotModified(ResponseCachingContext context)

test/Microsoft.AspNetCore.ResponseCaching.Tests/ResponseCachingMiddlewareTests.cs

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
using System.Collections.Generic;
66
using System.Threading.Tasks;
77
using Microsoft.AspNetCore.Http;
8+
using Microsoft.AspNetCore.Http.Features;
89
using Microsoft.AspNetCore.Http.Headers;
910
using Microsoft.AspNetCore.ResponseCaching.Internal;
11+
using Microsoft.Extensions.Internal;
1012
using Microsoft.Extensions.Logging.Testing;
1113
using Microsoft.Extensions.Primitives;
1214
using Microsoft.Net.Http.Headers;
@@ -717,14 +719,55 @@ public async Task FinalizeCacheBody_DoNotCache_IfBufferingDisabled()
717719
[Fact]
718720
public void ShimResponseStream_SecondInvocation_Throws()
719721
{
720-
var middleware = TestUtils.CreateTestMiddleware();
721-
var context = TestUtils.CreateTestContext();
722+
var httpContext = new DefaultHttpContext();
722723

723724
// Should not throw
724-
middleware.ShimResponseStream(context);
725+
ResponseCachingMiddleware.AddResponseCachingFeature(httpContext);
725726

726727
// Should throw
727-
Assert.ThrowsAny<InvalidOperationException>(() => middleware.ShimResponseStream(context));
728+
Assert.ThrowsAny<InvalidOperationException>(() => ResponseCachingMiddleware.AddResponseCachingFeature(httpContext));
729+
}
730+
731+
private class FakeResponseFeature : HttpResponseFeature
732+
{
733+
public override void OnStarting(Func<object, Task> callback, object state) { }
734+
}
735+
736+
[Fact]
737+
public async Task Invoke_CacheableRequest_AddsResponseCachingFeature()
738+
{
739+
var responseCachingFeatureAdded = false;
740+
var middleware = TestUtils.CreateTestMiddleware(next: httpContext =>
741+
{
742+
responseCachingFeatureAdded = httpContext.Features.Get<IResponseCachingFeature>() != null;
743+
return TaskCache.CompletedTask;
744+
},
745+
policyProvider: new ResponseCachingPolicyProvider());
746+
747+
var context = new DefaultHttpContext();
748+
context.Request.Method = HttpMethods.Get;
749+
context.Features.Set<IHttpResponseFeature>(new FakeResponseFeature());
750+
await middleware.Invoke(context);
751+
752+
Assert.True(responseCachingFeatureAdded);
753+
}
754+
755+
[Fact]
756+
public async Task Invoke_NonCacheableRequest_AddsResponseCachingFeature()
757+
{
758+
var responseCachingFeatureAdded = false;
759+
var middleware = TestUtils.CreateTestMiddleware(next: httpContext =>
760+
{
761+
responseCachingFeatureAdded = httpContext.Features.Get<IResponseCachingFeature>() != null;
762+
return TaskCache.CompletedTask;
763+
},
764+
policyProvider: new ResponseCachingPolicyProvider());
765+
766+
var context = new DefaultHttpContext();
767+
context.Request.Method = HttpMethods.Post;
768+
await middleware.Invoke(context);
769+
770+
Assert.True(responseCachingFeatureAdded);
728771
}
729772

730773
[Fact]

test/Microsoft.AspNetCore.ResponseCaching.Tests/TestUtils.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,17 @@ internal static IEnumerable<IWebHostBuilder> CreateBuildersWithResponseCaching(
103103
}
104104

105105
internal static ResponseCachingMiddleware CreateTestMiddleware(
106+
RequestDelegate next = null,
106107
IResponseCache cache = null,
107108
ResponseCachingOptions options = null,
108109
TestSink testSink = null,
109110
IResponseCachingKeyProvider keyProvider = null,
110111
IResponseCachingPolicyProvider policyProvider = null)
111112
{
113+
if (next == null)
114+
{
115+
next = httpContext => TaskCache.CompletedTask;
116+
}
112117
if (cache == null)
113118
{
114119
cache = new TestResponseCache();
@@ -127,7 +132,7 @@ internal static ResponseCachingMiddleware CreateTestMiddleware(
127132
}
128133

129134
return new ResponseCachingMiddleware(
130-
httpContext => TaskCache.CompletedTask,
135+
next,
131136
Options.Create(options),
132137
testSink == null ? (ILoggerFactory)NullLoggerFactory.Instance : new TestLoggerFactory(testSink, true),
133138
policyProvider,

0 commit comments

Comments
 (0)