Tigger caching header finalization on write #92
This commit is contained in:
parent
d43f05189a
commit
7190412979
|
|
@ -8,7 +8,10 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
|
||||||
{
|
{
|
||||||
public interface IResponseCache
|
public interface IResponseCache
|
||||||
{
|
{
|
||||||
|
IResponseCacheEntry Get(string key);
|
||||||
Task<IResponseCacheEntry> GetAsync(string key);
|
Task<IResponseCacheEntry> GetAsync(string key);
|
||||||
|
|
||||||
|
void Set(string key, IResponseCacheEntry entry, TimeSpan validFor);
|
||||||
Task SetAsync(string key, IResponseCacheEntry entry, TimeSpan validFor);
|
Task SetAsync(string key, IResponseCacheEntry entry, TimeSpan validFor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Extensions.Internal;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.ResponseCaching.Internal
|
namespace Microsoft.AspNetCore.ResponseCaching.Internal
|
||||||
{
|
{
|
||||||
|
|
@ -22,34 +22,39 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<IResponseCacheEntry> GetAsync(string key)
|
public IResponseCacheEntry Get(string key)
|
||||||
{
|
{
|
||||||
var entry = _cache.Get(key);
|
var entry = _cache.Get(key);
|
||||||
|
|
||||||
var memoryCachedResponse = entry as MemoryCachedResponse;
|
var memoryCachedResponse = entry as MemoryCachedResponse;
|
||||||
if (memoryCachedResponse != null)
|
if (memoryCachedResponse != null)
|
||||||
{
|
{
|
||||||
return Task.FromResult<IResponseCacheEntry>(new CachedResponse
|
return new CachedResponse
|
||||||
{
|
{
|
||||||
Created = memoryCachedResponse.Created,
|
Created = memoryCachedResponse.Created,
|
||||||
StatusCode = memoryCachedResponse.StatusCode,
|
StatusCode = memoryCachedResponse.StatusCode,
|
||||||
Headers = memoryCachedResponse.Headers,
|
Headers = memoryCachedResponse.Headers,
|
||||||
Body = new SegmentReadStream(memoryCachedResponse.BodySegments, memoryCachedResponse.BodyLength)
|
Body = new SegmentReadStream(memoryCachedResponse.BodySegments, memoryCachedResponse.BodyLength)
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return Task.FromResult(entry as IResponseCacheEntry);
|
return entry as IResponseCacheEntry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SetAsync(string key, IResponseCacheEntry entry, TimeSpan validFor)
|
public Task<IResponseCacheEntry> GetAsync(string key)
|
||||||
|
{
|
||||||
|
return Task.FromResult(Get(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set(string key, IResponseCacheEntry entry, TimeSpan validFor)
|
||||||
{
|
{
|
||||||
var cachedResponse = entry as CachedResponse;
|
var cachedResponse = entry as CachedResponse;
|
||||||
if (cachedResponse != null)
|
if (cachedResponse != null)
|
||||||
{
|
{
|
||||||
var segmentStream = new SegmentWriteStream(StreamUtilities.BodySegmentSize);
|
var segmentStream = new SegmentWriteStream(StreamUtilities.BodySegmentSize);
|
||||||
await cachedResponse.Body.CopyToAsync(segmentStream);
|
cachedResponse.Body.CopyTo(segmentStream);
|
||||||
|
|
||||||
_cache.Set(
|
_cache.Set(
|
||||||
key,
|
key,
|
||||||
|
|
@ -77,5 +82,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task SetAsync(string key, IResponseCacheEntry entry, TimeSpan validFor)
|
||||||
|
{
|
||||||
|
Set(key, entry, validFor);
|
||||||
|
return TaskCache.CompletedTask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Http" Version="1.2.0-*" />
|
<PackageReference Include="Microsoft.AspNetCore.Http" Version="1.2.0-*" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="1.2.0-*" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="1.2.0-*" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="1.2.0-*" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="1.2.0-*" />
|
||||||
<PackageReference Include="Microsoft.Extensions.TaskCache.Sources" Version="1.2.0-*" PrivateAssets="All"/>
|
<PackageReference Include="Microsoft.Extensions.TaskCache.Sources" Version="1.2.0-*" PrivateAssets="All" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
private readonly IResponseCachingPolicyProvider _policyProvider;
|
private readonly IResponseCachingPolicyProvider _policyProvider;
|
||||||
private readonly IResponseCache _cache;
|
private readonly IResponseCache _cache;
|
||||||
private readonly IResponseCachingKeyProvider _keyProvider;
|
private readonly IResponseCachingKeyProvider _keyProvider;
|
||||||
private readonly Func<object, Task> _onStartingCallback;
|
|
||||||
|
|
||||||
public ResponseCachingMiddleware(
|
public ResponseCachingMiddleware(
|
||||||
RequestDelegate next,
|
RequestDelegate next,
|
||||||
|
|
@ -66,7 +65,6 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
_policyProvider = policyProvider;
|
_policyProvider = policyProvider;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
_keyProvider = keyProvider;
|
_keyProvider = keyProvider;
|
||||||
_onStartingCallback = state => OnResponseStartingAsync((ResponseCachingContext)state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Invoke(HttpContext httpContext)
|
public async Task Invoke(HttpContext httpContext)
|
||||||
|
|
@ -90,13 +88,10 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Subscribe to OnStarting event
|
|
||||||
httpContext.Response.OnStarting(_onStartingCallback, context);
|
|
||||||
|
|
||||||
await _next(httpContext);
|
await _next(httpContext);
|
||||||
|
|
||||||
// If there was no response body, check the response headers now. We can cache things like redirects.
|
// If there was no response body, check the response headers now. We can cache things like redirects.
|
||||||
await OnResponseStartingAsync(context);
|
await StartResponseAsync(context);
|
||||||
|
|
||||||
// Finalize the cache entry
|
// Finalize the cache entry
|
||||||
await FinalizeCacheBodyAsync(context);
|
await FinalizeCacheBodyAsync(context);
|
||||||
|
|
@ -219,10 +214,17 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task FinalizeCacheHeadersAsync(ResponseCachingContext context)
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finalize cache headers.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <returns><c>true</c> if a vary by entry needs to be stored in the cache; otherwise <c>false</c>.</returns>
|
||||||
|
private bool OnFinalizeCacheHeaders(ResponseCachingContext context)
|
||||||
{
|
{
|
||||||
if (_policyProvider.IsResponseCacheable(context))
|
if (_policyProvider.IsResponseCacheable(context))
|
||||||
{
|
{
|
||||||
|
var storeVaryByEntry = false;
|
||||||
context.ShouldCacheResponse = true;
|
context.ShouldCacheResponse = true;
|
||||||
|
|
||||||
// Create the cache entry now
|
// Create the cache entry now
|
||||||
|
|
@ -262,7 +264,7 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
|
|
||||||
// Always overwrite the CachedVaryByRules to update the expiry information
|
// Always overwrite the CachedVaryByRules to update the expiry information
|
||||||
_logger.LogVaryByRulesUpdated(normalizedVaryHeaders, normalizedVaryQueryKeys);
|
_logger.LogVaryByRulesUpdated(normalizedVaryHeaders, normalizedVaryQueryKeys);
|
||||||
await _cache.SetAsync(context.BaseKey, context.CachedVaryByRules, context.CachedResponseValidFor);
|
storeVaryByEntry = true;
|
||||||
|
|
||||||
context.StorageVaryKey = _keyProvider.CreateStorageVaryByKey(context);
|
context.StorageVaryKey = _keyProvider.CreateStorageVaryByKey(context);
|
||||||
}
|
}
|
||||||
|
|
@ -290,13 +292,31 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
context.CachedResponse.Headers[header.Key] = header.Value;
|
context.CachedResponse.Headers[header.Key] = header.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return storeVaryByEntry;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
context.ResponseCachingStream.DisableBuffering();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void FinalizeCacheHeaders(ResponseCachingContext context)
|
||||||
|
{
|
||||||
|
if (OnFinalizeCacheHeaders(context))
|
||||||
{
|
{
|
||||||
context.ResponseCachingStream.DisableBuffering();
|
_cache.Set(context.BaseKey, context.CachedVaryByRules, context.CachedResponseValidFor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal Task FinalizeCacheHeadersAsync(ResponseCachingContext context)
|
||||||
|
{
|
||||||
|
if (OnFinalizeCacheHeaders(context))
|
||||||
|
{
|
||||||
|
return _cache.SetAsync(context.BaseKey, context.CachedVaryByRules, context.CachedResponseValidFor);
|
||||||
|
}
|
||||||
|
return TaskCache.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
internal async Task FinalizeCacheBodyAsync(ResponseCachingContext context)
|
internal async Task FinalizeCacheBodyAsync(ResponseCachingContext context)
|
||||||
{
|
{
|
||||||
if (context.ShouldCacheResponse && context.ResponseCachingStream.BufferingEnabled)
|
if (context.ShouldCacheResponse && context.ResponseCachingStream.BufferingEnabled)
|
||||||
|
|
@ -327,19 +347,38 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Task OnResponseStartingAsync(ResponseCachingContext context)
|
/// <summary>
|
||||||
|
/// Mark the response as started and set the response time if no reponse was started yet.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <returns><c>true</c> if the response was not started before this call; otherwise <c>false</c>.</returns>
|
||||||
|
private bool OnStartResponse(ResponseCachingContext context)
|
||||||
{
|
{
|
||||||
if (!context.ResponseStarted)
|
if (!context.ResponseStarted)
|
||||||
{
|
{
|
||||||
context.ResponseStarted = true;
|
context.ResponseStarted = true;
|
||||||
context.ResponseTime = _options.SystemClock.UtcNow;
|
context.ResponseTime = _options.SystemClock.UtcNow;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void StartResponse(ResponseCachingContext context)
|
||||||
|
{
|
||||||
|
if (OnStartResponse(context))
|
||||||
|
{
|
||||||
|
FinalizeCacheHeaders(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Task StartResponseAsync(ResponseCachingContext context)
|
||||||
|
{
|
||||||
|
if (OnStartResponse(context))
|
||||||
|
{
|
||||||
return FinalizeCacheHeadersAsync(context);
|
return FinalizeCacheHeadersAsync(context);
|
||||||
}
|
}
|
||||||
else
|
return TaskCache.CompletedTask;
|
||||||
{
|
|
||||||
return TaskCache.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void AddResponseCachingFeature(HttpContext context)
|
internal static void AddResponseCachingFeature(HttpContext context)
|
||||||
|
|
@ -355,7 +394,12 @@ namespace Microsoft.AspNetCore.ResponseCaching
|
||||||
{
|
{
|
||||||
// Shim response stream
|
// Shim response stream
|
||||||
context.OriginalResponseStream = context.HttpContext.Response.Body;
|
context.OriginalResponseStream = context.HttpContext.Response.Body;
|
||||||
context.ResponseCachingStream = new ResponseCachingStream(context.OriginalResponseStream, _options.MaximumBodySize, StreamUtilities.BodySegmentSize);
|
context.ResponseCachingStream = new ResponseCachingStream(
|
||||||
|
context.OriginalResponseStream,
|
||||||
|
_options.MaximumBodySize,
|
||||||
|
StreamUtilities.BodySegmentSize,
|
||||||
|
() => StartResponse(context),
|
||||||
|
() => StartResponseAsync(context));
|
||||||
context.HttpContext.Response.Body = context.ResponseCachingStream;
|
context.HttpContext.Response.Body = context.ResponseCachingStream;
|
||||||
|
|
||||||
// Shim IHttpSendFileFeature
|
// Shim IHttpSendFileFeature
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,16 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
|
||||||
private readonly long _maxBufferSize;
|
private readonly long _maxBufferSize;
|
||||||
private readonly int _segmentSize;
|
private readonly int _segmentSize;
|
||||||
private SegmentWriteStream _segmentWriteStream;
|
private SegmentWriteStream _segmentWriteStream;
|
||||||
|
private Action _startResponseCallback;
|
||||||
|
private Func<Task> _startResponseCallbackAsync;
|
||||||
|
|
||||||
internal ResponseCachingStream(Stream innerStream, long maxBufferSize, int segmentSize)
|
internal ResponseCachingStream(Stream innerStream, long maxBufferSize, int segmentSize, Action startResponseCallback, Func<Task> startResponseCallbackAsync)
|
||||||
{
|
{
|
||||||
_innerStream = innerStream;
|
_innerStream = innerStream;
|
||||||
_maxBufferSize = maxBufferSize;
|
_maxBufferSize = maxBufferSize;
|
||||||
_segmentSize = segmentSize;
|
_segmentSize = segmentSize;
|
||||||
|
_startResponseCallback = startResponseCallback;
|
||||||
|
_startResponseCallbackAsync = startResponseCallbackAsync;
|
||||||
_segmentWriteStream = new SegmentWriteStream(_segmentSize);
|
_segmentWriteStream = new SegmentWriteStream(_segmentSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,10 +75,32 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Flush()
|
public override void Flush()
|
||||||
=> _innerStream.Flush();
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_startResponseCallback();
|
||||||
|
_innerStream.Flush();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
DisableBuffering();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override Task FlushAsync(CancellationToken cancellationToken)
|
public override async Task FlushAsync(CancellationToken cancellationToken)
|
||||||
=> _innerStream.FlushAsync();
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _startResponseCallbackAsync();
|
||||||
|
await _innerStream.FlushAsync();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
DisableBuffering();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Underlying stream is write-only, no need to override other read related methods
|
// Underlying stream is write-only, no need to override other read related methods
|
||||||
public override int Read(byte[] buffer, int offset, int count)
|
public override int Read(byte[] buffer, int offset, int count)
|
||||||
|
|
@ -84,6 +110,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
_startResponseCallback();
|
||||||
_innerStream.Write(buffer, offset, count);
|
_innerStream.Write(buffer, offset, count);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|
@ -109,6 +136,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
await _startResponseCallbackAsync();
|
||||||
await _innerStream.WriteAsync(buffer, offset, count, cancellationToken);
|
await _innerStream.WriteAsync(buffer, offset, count, cancellationToken);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|
|
||||||
|
|
@ -359,7 +359,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task OnResponseStartingAsync_IfAllowResponseCaptureIsTrue_SetsResponseTime()
|
public async Task StartResponsegAsync_IfAllowResponseCaptureIsTrue_SetsResponseTime()
|
||||||
{
|
{
|
||||||
var clock = new TestClock
|
var clock = new TestClock
|
||||||
{
|
{
|
||||||
|
|
@ -372,13 +372,13 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
var context = TestUtils.CreateTestContext();
|
var context = TestUtils.CreateTestContext();
|
||||||
context.ResponseTime = null;
|
context.ResponseTime = null;
|
||||||
|
|
||||||
await middleware.OnResponseStartingAsync(context);
|
await middleware.StartResponseAsync(context);
|
||||||
|
|
||||||
Assert.Equal(clock.UtcNow, context.ResponseTime);
|
Assert.Equal(clock.UtcNow, context.ResponseTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task OnResponseStartingAsync_IfAllowResponseCaptureIsTrue_SetsResponseTimeOnlyOnce()
|
public async Task StartResponseAsync_IfAllowResponseCaptureIsTrue_SetsResponseTimeOnlyOnce()
|
||||||
{
|
{
|
||||||
var clock = new TestClock
|
var clock = new TestClock
|
||||||
{
|
{
|
||||||
|
|
@ -392,12 +392,12 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
var initialTime = clock.UtcNow;
|
var initialTime = clock.UtcNow;
|
||||||
context.ResponseTime = null;
|
context.ResponseTime = null;
|
||||||
|
|
||||||
await middleware.OnResponseStartingAsync(context);
|
await middleware.StartResponseAsync(context);
|
||||||
Assert.Equal(initialTime, context.ResponseTime);
|
Assert.Equal(initialTime, context.ResponseTime);
|
||||||
|
|
||||||
clock.UtcNow += TimeSpan.FromSeconds(10);
|
clock.UtcNow += TimeSpan.FromSeconds(10);
|
||||||
|
|
||||||
await middleware.OnResponseStartingAsync(context);
|
await middleware.StartResponseAsync(context);
|
||||||
Assert.NotEqual(clock.UtcNow, context.ResponseTime);
|
Assert.NotEqual(clock.UtcNow, context.ResponseTime);
|
||||||
Assert.Equal(initialTime, context.ResponseTime);
|
Assert.Equal(initialTime, context.ResponseTime);
|
||||||
}
|
}
|
||||||
|
|
@ -790,10 +790,9 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache);
|
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, cache: cache);
|
||||||
var context = TestUtils.CreateTestContext();
|
var context = TestUtils.CreateTestContext();
|
||||||
|
|
||||||
context.ShouldCacheResponse = false;
|
|
||||||
middleware.ShimResponseStream(context);
|
middleware.ShimResponseStream(context);
|
||||||
await context.HttpContext.Response.WriteAsync(new string('0', 10));
|
await context.HttpContext.Response.WriteAsync(new string('0', 10));
|
||||||
|
context.ShouldCacheResponse = false;
|
||||||
|
|
||||||
await middleware.FinalizeCacheBodyAsync(context);
|
await middleware.FinalizeCacheBodyAsync(context);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Net;
|
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
@ -233,11 +232,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ServesCachedContent_IfVaryHeader_Matches()
|
public async void ServesCachedContent_IfVaryHeader_Matches()
|
||||||
{
|
{
|
||||||
var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
|
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context => context.Response.Headers[HeaderNames.Vary] = HeaderNames.From);
|
||||||
{
|
|
||||||
context.Response.Headers[HeaderNames.Vary] = HeaderNames.From;
|
|
||||||
await TestUtils.TestRequestDelegate(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var builder in builders)
|
foreach (var builder in builders)
|
||||||
{
|
{
|
||||||
|
|
@ -256,11 +251,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ServesFreshContent_IfVaryHeader_Mismatches()
|
public async void ServesFreshContent_IfVaryHeader_Mismatches()
|
||||||
{
|
{
|
||||||
var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
|
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context => context.Response.Headers[HeaderNames.Vary] = HeaderNames.From);
|
||||||
{
|
|
||||||
context.Response.Headers[HeaderNames.Vary] = HeaderNames.From;
|
|
||||||
await TestUtils.TestRequestDelegate(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var builder in builders)
|
foreach (var builder in builders)
|
||||||
{
|
{
|
||||||
|
|
@ -280,11 +271,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ServesCachedContent_IfVaryQueryKeys_Matches()
|
public async void ServesCachedContent_IfVaryQueryKeys_Matches()
|
||||||
{
|
{
|
||||||
var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
|
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context => context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "query" });
|
||||||
{
|
|
||||||
context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "query" };
|
|
||||||
await TestUtils.TestRequestDelegate(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var builder in builders)
|
foreach (var builder in builders)
|
||||||
{
|
{
|
||||||
|
|
@ -302,11 +289,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ServesCachedContent_IfVaryQueryKeysExplicit_Matches_QueryKeyCaseInsensitive()
|
public async void ServesCachedContent_IfVaryQueryKeysExplicit_Matches_QueryKeyCaseInsensitive()
|
||||||
{
|
{
|
||||||
var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
|
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context => context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "QueryA", "queryb" });
|
||||||
{
|
|
||||||
context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "QueryA", "queryb" };
|
|
||||||
await TestUtils.TestRequestDelegate(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var builder in builders)
|
foreach (var builder in builders)
|
||||||
{
|
{
|
||||||
|
|
@ -324,11 +307,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ServesCachedContent_IfVaryQueryKeyStar_Matches_QueryKeyCaseInsensitive()
|
public async void ServesCachedContent_IfVaryQueryKeyStar_Matches_QueryKeyCaseInsensitive()
|
||||||
{
|
{
|
||||||
var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
|
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context => context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "*" });
|
||||||
{
|
|
||||||
context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "*" };
|
|
||||||
await TestUtils.TestRequestDelegate(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var builder in builders)
|
foreach (var builder in builders)
|
||||||
{
|
{
|
||||||
|
|
@ -346,11 +325,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ServesCachedContent_IfVaryQueryKeyExplicit_Matches_OrderInsensitive()
|
public async void ServesCachedContent_IfVaryQueryKeyExplicit_Matches_OrderInsensitive()
|
||||||
{
|
{
|
||||||
var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
|
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context => context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "QueryB", "QueryA" });
|
||||||
{
|
|
||||||
context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "QueryB", "QueryA" };
|
|
||||||
await TestUtils.TestRequestDelegate(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var builder in builders)
|
foreach (var builder in builders)
|
||||||
{
|
{
|
||||||
|
|
@ -368,11 +343,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ServesCachedContent_IfVaryQueryKeyStar_Matches_OrderInsensitive()
|
public async void ServesCachedContent_IfVaryQueryKeyStar_Matches_OrderInsensitive()
|
||||||
{
|
{
|
||||||
var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
|
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context => context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "*" });
|
||||||
{
|
|
||||||
context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "*" };
|
|
||||||
await TestUtils.TestRequestDelegate(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var builder in builders)
|
foreach (var builder in builders)
|
||||||
{
|
{
|
||||||
|
|
@ -390,11 +361,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ServesFreshContent_IfVaryQueryKey_Mismatches()
|
public async void ServesFreshContent_IfVaryQueryKey_Mismatches()
|
||||||
{
|
{
|
||||||
var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
|
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context => context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "query" });
|
||||||
{
|
|
||||||
context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "query" };
|
|
||||||
await TestUtils.TestRequestDelegate(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var builder in builders)
|
foreach (var builder in builders)
|
||||||
{
|
{
|
||||||
|
|
@ -412,11 +379,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ServesFreshContent_IfVaryQueryKeyExplicit_Mismatch_QueryKeyCaseSensitive()
|
public async void ServesFreshContent_IfVaryQueryKeyExplicit_Mismatch_QueryKeyCaseSensitive()
|
||||||
{
|
{
|
||||||
var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
|
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context => context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "QueryA", "QueryB" });
|
||||||
{
|
|
||||||
context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "QueryA", "QueryB" };
|
|
||||||
await TestUtils.TestRequestDelegate(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var builder in builders)
|
foreach (var builder in builders)
|
||||||
{
|
{
|
||||||
|
|
@ -434,11 +397,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ServesFreshContent_IfVaryQueryKeyStar_Mismatch_QueryKeyValueCaseSensitive()
|
public async void ServesFreshContent_IfVaryQueryKeyStar_Mismatch_QueryKeyValueCaseSensitive()
|
||||||
{
|
{
|
||||||
var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
|
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context => context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "*" });
|
||||||
{
|
|
||||||
context.Features.Get<IResponseCachingFeature>().VaryByQueryKeys = new[] { "*" };
|
|
||||||
await TestUtils.TestRequestDelegate(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var builder in builders)
|
foreach (var builder in builders)
|
||||||
{
|
{
|
||||||
|
|
@ -501,11 +460,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ServesFreshContent_IfSetCookie_IsSpecified()
|
public async void ServesFreshContent_IfSetCookie_IsSpecified()
|
||||||
{
|
{
|
||||||
var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
|
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context => context.Response.Headers[HeaderNames.SetCookie] = "cookieName=cookieValue");
|
||||||
{
|
|
||||||
var headers = context.Response.Headers[HeaderNames.SetCookie] = "cookieName=cookieValue";
|
|
||||||
await TestUtils.TestRequestDelegate(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var builder in builders)
|
foreach (var builder in builders)
|
||||||
{
|
{
|
||||||
|
|
@ -557,11 +512,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
await next.Invoke();
|
await next.Invoke();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
requestDelegate: async (context) =>
|
contextAction: async context => await context.Features.Get<IHttpSendFileFeature>().SendFileAsync("dummy", 0, 0, CancellationToken.None));
|
||||||
{
|
|
||||||
await context.Features.Get<IHttpSendFileFeature>().SendFileAsync("dummy", 0, 0, CancellationToken.None);
|
|
||||||
await TestUtils.TestRequestDelegate(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var builder in builders)
|
foreach (var builder in builders)
|
||||||
{
|
{
|
||||||
|
|
@ -623,14 +574,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ServesFreshContent_IfInitialResponseContainsNoStore()
|
public async void ServesFreshContent_IfInitialResponseContainsNoStore()
|
||||||
{
|
{
|
||||||
var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
|
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context => context.Response.Headers[HeaderNames.CacheControl] = CacheControlHeaderValue.NoStoreString);
|
||||||
{
|
|
||||||
var headers = context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue()
|
|
||||||
{
|
|
||||||
NoStore = true
|
|
||||||
};
|
|
||||||
await TestUtils.TestRequestDelegate(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var builder in builders)
|
foreach (var builder in builders)
|
||||||
{
|
{
|
||||||
|
|
@ -687,11 +631,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void Serves304_IfIfNoneMatch_Satisfied()
|
public async void Serves304_IfIfNoneMatch_Satisfied()
|
||||||
{
|
{
|
||||||
var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
|
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context => context.Response.GetTypedHeaders().ETag = new EntityTagHeaderValue("\"E1\""));
|
||||||
{
|
|
||||||
var headers = context.Response.GetTypedHeaders().ETag = new EntityTagHeaderValue("\"E1\"");
|
|
||||||
await TestUtils.TestRequestDelegate(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var builder in builders)
|
foreach (var builder in builders)
|
||||||
{
|
{
|
||||||
|
|
@ -711,11 +651,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ServesCachedContent_IfIfNoneMatch_NotSatisfied()
|
public async void ServesCachedContent_IfIfNoneMatch_NotSatisfied()
|
||||||
{
|
{
|
||||||
var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
|
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context => context.Response.GetTypedHeaders().ETag = new EntityTagHeaderValue("\"E1\""));
|
||||||
{
|
|
||||||
var headers = context.Response.GetTypedHeaders().ETag = new EntityTagHeaderValue("\"E1\"");
|
|
||||||
await TestUtils.TestRequestDelegate(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var builder in builders)
|
foreach (var builder in builders)
|
||||||
{
|
{
|
||||||
|
|
@ -797,11 +733,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ServesCachedContent_WithoutReplacingCachedVaryBy_OnCacheMiss()
|
public async void ServesCachedContent_WithoutReplacingCachedVaryBy_OnCacheMiss()
|
||||||
{
|
{
|
||||||
var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
|
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context => context.Response.Headers[HeaderNames.Vary] = HeaderNames.From);
|
||||||
{
|
|
||||||
context.Response.Headers[HeaderNames.Vary] = HeaderNames.From;
|
|
||||||
await TestUtils.TestRequestDelegate(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var builder in builders)
|
foreach (var builder in builders)
|
||||||
{
|
{
|
||||||
|
|
@ -823,11 +755,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ServesFreshContent_IfCachedVaryByUpdated_OnCacheMiss()
|
public async void ServesFreshContent_IfCachedVaryByUpdated_OnCacheMiss()
|
||||||
{
|
{
|
||||||
var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
|
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context => context.Response.Headers[HeaderNames.Vary] = context.Request.Headers[HeaderNames.Pragma]);
|
||||||
{
|
|
||||||
context.Response.Headers[HeaderNames.Vary] = context.Request.Headers[HeaderNames.Pragma];
|
|
||||||
await TestUtils.TestRequestDelegate(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var builder in builders)
|
foreach (var builder in builders)
|
||||||
{
|
{
|
||||||
|
|
@ -858,11 +786,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ServesCachedContent_IfCachedVaryByNotUpdated_OnCacheMiss()
|
public async void ServesCachedContent_IfCachedVaryByNotUpdated_OnCacheMiss()
|
||||||
{
|
{
|
||||||
var builders = TestUtils.CreateBuildersWithResponseCaching(requestDelegate: async (context) =>
|
var builders = TestUtils.CreateBuildersWithResponseCaching(contextAction: context => context.Response.Headers[HeaderNames.Vary] = context.Request.Headers[HeaderNames.Pragma]);
|
||||||
{
|
|
||||||
context.Response.Headers[HeaderNames.Vary] = context.Request.Headers[HeaderNames.Pragma];
|
|
||||||
await TestUtils.TestRequestDelegate(context);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var builder in builders)
|
foreach (var builder in builders)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
|
@ -32,7 +33,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
StreamUtilities.BodySegmentSize = 10;
|
StreamUtilities.BodySegmentSize = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static RequestDelegate TestRequestDelegate = async context =>
|
private static bool TestRequestDelegate(HttpContext context, string guid)
|
||||||
{
|
{
|
||||||
var headers = context.Response.GetTypedHeaders();
|
var headers = context.Response.GetTypedHeaders();
|
||||||
|
|
||||||
|
|
@ -42,7 +43,6 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
headers.Expires = DateTimeOffset.Now.AddSeconds(int.Parse(expires));
|
headers.Expires = DateTimeOffset.Now.AddSeconds(int.Parse(expires));
|
||||||
}
|
}
|
||||||
|
|
||||||
var uniqueId = Guid.NewGuid().ToString();
|
|
||||||
if (headers.CacheControl == null)
|
if (headers.CacheControl == null)
|
||||||
{
|
{
|
||||||
headers.CacheControl = new CacheControlHeaderValue
|
headers.CacheControl = new CacheControlHeaderValue
|
||||||
|
|
@ -57,13 +57,33 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
headers.CacheControl.MaxAge = string.IsNullOrEmpty(expires) ? TimeSpan.FromSeconds(10) : (TimeSpan?)null;
|
headers.CacheControl.MaxAge = string.IsNullOrEmpty(expires) ? TimeSpan.FromSeconds(10) : (TimeSpan?)null;
|
||||||
}
|
}
|
||||||
headers.Date = DateTimeOffset.UtcNow;
|
headers.Date = DateTimeOffset.UtcNow;
|
||||||
headers.Headers["X-Value"] = uniqueId;
|
headers.Headers["X-Value"] = guid;
|
||||||
|
|
||||||
if (context.Request.Method != "HEAD")
|
if (context.Request.Method != "HEAD")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static async Task TestRequestDelegateWriteAsync(HttpContext context)
|
||||||
|
{
|
||||||
|
var uniqueId = Guid.NewGuid().ToString();
|
||||||
|
if (TestRequestDelegate(context, uniqueId))
|
||||||
{
|
{
|
||||||
await context.Response.WriteAsync(uniqueId);
|
await context.Response.WriteAsync(uniqueId);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
internal static Task TestRequestDelegateWrite(HttpContext context)
|
||||||
|
{
|
||||||
|
var uniqueId = Guid.NewGuid().ToString();
|
||||||
|
if (TestRequestDelegate(context, uniqueId))
|
||||||
|
{
|
||||||
|
context.Response.Write(uniqueId);
|
||||||
|
}
|
||||||
|
return TaskCache.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
internal static IResponseCachingKeyProvider CreateTestKeyProvider()
|
internal static IResponseCachingKeyProvider CreateTestKeyProvider()
|
||||||
{
|
{
|
||||||
|
|
@ -78,37 +98,64 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
internal static IEnumerable<IWebHostBuilder> CreateBuildersWithResponseCaching(
|
internal static IEnumerable<IWebHostBuilder> CreateBuildersWithResponseCaching(
|
||||||
Action<IApplicationBuilder> configureDelegate = null,
|
Action<IApplicationBuilder> configureDelegate = null,
|
||||||
ResponseCachingOptions options = null,
|
ResponseCachingOptions options = null,
|
||||||
RequestDelegate requestDelegate = null)
|
Action<HttpContext> contextAction = null)
|
||||||
|
{
|
||||||
|
return CreateBuildersWithResponseCaching(configureDelegate, options, new RequestDelegate[]
|
||||||
|
{
|
||||||
|
context =>
|
||||||
|
{
|
||||||
|
contextAction?.Invoke(context);
|
||||||
|
return TestRequestDelegateWrite(context);
|
||||||
|
},
|
||||||
|
context =>
|
||||||
|
{
|
||||||
|
contextAction?.Invoke(context);
|
||||||
|
return TestRequestDelegateWriteAsync(context);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<IWebHostBuilder> CreateBuildersWithResponseCaching(
|
||||||
|
Action<IApplicationBuilder> configureDelegate = null,
|
||||||
|
ResponseCachingOptions options = null,
|
||||||
|
IEnumerable<RequestDelegate> requestDelegates = null)
|
||||||
{
|
{
|
||||||
if (configureDelegate == null)
|
if (configureDelegate == null)
|
||||||
{
|
{
|
||||||
configureDelegate = app => { };
|
configureDelegate = app => { };
|
||||||
}
|
}
|
||||||
if (requestDelegate == null)
|
if (requestDelegates == null)
|
||||||
{
|
{
|
||||||
requestDelegate = TestRequestDelegate;
|
requestDelegates = new RequestDelegate[]
|
||||||
|
{
|
||||||
|
TestRequestDelegateWriteAsync,
|
||||||
|
TestRequestDelegateWrite
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test with in memory ResponseCache
|
foreach (var requestDelegate in requestDelegates)
|
||||||
yield return new WebHostBuilder()
|
{
|
||||||
.ConfigureServices(services =>
|
// Test with in memory ResponseCache
|
||||||
{
|
yield return new WebHostBuilder()
|
||||||
services.AddResponseCaching(responseCachingOptions =>
|
.ConfigureServices(services =>
|
||||||
{
|
{
|
||||||
if (options != null)
|
services.AddResponseCaching(responseCachingOptions =>
|
||||||
{
|
{
|
||||||
responseCachingOptions.MaximumBodySize = options.MaximumBodySize;
|
if (options != null)
|
||||||
responseCachingOptions.UseCaseSensitivePaths = options.UseCaseSensitivePaths;
|
{
|
||||||
responseCachingOptions.SystemClock = options.SystemClock;
|
responseCachingOptions.MaximumBodySize = options.MaximumBodySize;
|
||||||
}
|
responseCachingOptions.UseCaseSensitivePaths = options.UseCaseSensitivePaths;
|
||||||
|
responseCachingOptions.SystemClock = options.SystemClock;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.Configure(app =>
|
||||||
|
{
|
||||||
|
configureDelegate(app);
|
||||||
|
app.UseResponseCaching();
|
||||||
|
app.Run(requestDelegate);
|
||||||
});
|
});
|
||||||
})
|
}
|
||||||
.Configure(app =>
|
|
||||||
{
|
|
||||||
configureDelegate(app);
|
|
||||||
app.UseResponseCaching();
|
|
||||||
app.Run(requestDelegate);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static ResponseCachingMiddleware CreateTestMiddleware(
|
internal static ResponseCachingMiddleware CreateTestMiddleware(
|
||||||
|
|
@ -181,6 +228,25 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static class HttpResponseWritingExtensions
|
||||||
|
{
|
||||||
|
internal static void Write(this HttpResponse response, string text)
|
||||||
|
{
|
||||||
|
if (response == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(response));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] data = Encoding.UTF8.GetBytes(text);
|
||||||
|
response.Body.Write(data, 0, data.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal class LoggedMessage
|
internal class LoggedMessage
|
||||||
{
|
{
|
||||||
internal static LoggedMessage RequestMethodNotCacheable => new LoggedMessage(1, LogLevel.Debug);
|
internal static LoggedMessage RequestMethodNotCacheable => new LoggedMessage(1, LogLevel.Debug);
|
||||||
|
|
@ -289,23 +355,33 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests
|
||||||
public int GetCount { get; private set; }
|
public int GetCount { get; private set; }
|
||||||
public int SetCount { get; private set; }
|
public int SetCount { get; private set; }
|
||||||
|
|
||||||
public Task<IResponseCacheEntry> GetAsync(string key)
|
public IResponseCacheEntry Get(string key)
|
||||||
{
|
{
|
||||||
GetCount++;
|
GetCount++;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return Task.FromResult(_storage[key]);
|
return _storage[key];
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
return Task.FromResult<IResponseCacheEntry>(null);
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<IResponseCacheEntry> GetAsync(string key)
|
||||||
|
{
|
||||||
|
return Task.FromResult(Get(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set(string key, IResponseCacheEntry entry, TimeSpan validFor)
|
||||||
|
{
|
||||||
|
SetCount++;
|
||||||
|
_storage[key] = entry;
|
||||||
|
}
|
||||||
|
|
||||||
public Task SetAsync(string key, IResponseCacheEntry entry, TimeSpan validFor)
|
public Task SetAsync(string key, IResponseCacheEntry entry, TimeSpan validFor)
|
||||||
{
|
{
|
||||||
SetCount++;
|
Set(key, entry, validFor);
|
||||||
_storage[key] = entry;
|
|
||||||
return TaskCache.CompletedTask;
|
return TaskCache.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue