diff --git a/src/Microsoft.AspNetCore.ResponseCaching/Interfaces/IResponseCacheStore.cs b/src/Microsoft.AspNetCore.ResponseCaching/Interfaces/IResponseCacheStore.cs index 90998a71d4..55ed237786 100644 --- a/src/Microsoft.AspNetCore.ResponseCaching/Interfaces/IResponseCacheStore.cs +++ b/src/Microsoft.AspNetCore.ResponseCaching/Interfaces/IResponseCacheStore.cs @@ -2,13 +2,14 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Threading.Tasks; namespace Microsoft.AspNetCore.ResponseCaching { public interface IResponseCacheStore { - object Get(string key); - void Set(string key, object entry, TimeSpan validFor); - void Remove(string key); + Task GetAsync(string key); + Task SetAsync(string key, object entry, TimeSpan validFor); + Task RemoveAsync(string key); } } diff --git a/src/Microsoft.AspNetCore.ResponseCaching/Internal/DistributedResponseCacheStore.cs b/src/Microsoft.AspNetCore.ResponseCaching/Internal/DistributedResponseCacheStore.cs index 88fa05f3ea..170f7e65cd 100644 --- a/src/Microsoft.AspNetCore.ResponseCaching/Internal/DistributedResponseCacheStore.cs +++ b/src/Microsoft.AspNetCore.ResponseCaching/Internal/DistributedResponseCacheStore.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Threading.Tasks; using Microsoft.Extensions.Caching.Distributed; namespace Microsoft.AspNetCore.ResponseCaching.Internal @@ -20,11 +21,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal _cache = cache; } - public object Get(string key) + public async Task GetAsync(string key) { try { - return CacheEntrySerializer.Deserialize(_cache.Get(key)); + return CacheEntrySerializer.Deserialize(await _cache.GetAsync(key)); } catch { @@ -32,20 +33,20 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal } } - public void Remove(string key) + public async Task RemoveAsync(string key) { try { - _cache.Remove(key); + await _cache.RemoveAsync(key); } catch { } } - public void Set(string key, object entry, TimeSpan validFor) + public async Task SetAsync(string key, object entry, TimeSpan validFor) { try { - _cache.Set( + await _cache.SetAsync( key, CacheEntrySerializer.Serialize(entry), new DistributedCacheEntryOptions() diff --git a/src/Microsoft.AspNetCore.ResponseCaching/Internal/MemoryResponseCacheStore.cs b/src/Microsoft.AspNetCore.ResponseCaching/Internal/MemoryResponseCacheStore.cs index b92693137b..33b7f4367b 100644 --- a/src/Microsoft.AspNetCore.ResponseCaching/Internal/MemoryResponseCacheStore.cs +++ b/src/Microsoft.AspNetCore.ResponseCaching/Internal/MemoryResponseCacheStore.cs @@ -2,7 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Threading.Tasks; using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.ResponseCaching.Internal { @@ -20,17 +22,18 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal _cache = cache; } - public object Get(string key) + public Task GetAsync(string key) { - return _cache.Get(key); + return Task.FromResult(_cache.Get(key)); } - public void Remove(string key) + public Task RemoveAsync(string key) { _cache.Remove(key); + return TaskCache.CompletedTask; } - public void Set(string key, object entry, TimeSpan validFor) + public Task SetAsync(string key, object entry, TimeSpan validFor) { _cache.Set( key, @@ -39,6 +42,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Internal { AbsoluteExpirationRelativeToNow = validFor }); + return TaskCache.CompletedTask; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.ResponseCaching/ResponseCacheMiddleware.cs b/src/Microsoft.AspNetCore.ResponseCaching/ResponseCacheMiddleware.cs index 4b0889fc5d..850bfdb236 100644 --- a/src/Microsoft.AspNetCore.ResponseCaching/ResponseCacheMiddleware.cs +++ b/src/Microsoft.AspNetCore.ResponseCaching/ResponseCacheMiddleware.cs @@ -60,11 +60,7 @@ namespace Microsoft.AspNetCore.ResponseCaching _options = options.Value; _policyProvider = policyProvider; _keyProvider = keyProvider; - _onStartingCallback = state => - { - OnResponseStarting((ResponseCacheContext)state); - return TaskCache.CompletedTask; - }; + _onStartingCallback = state => OnResponseStartingAsync((ResponseCacheContext)state); } public async Task Invoke(HttpContext httpContext) @@ -91,10 +87,10 @@ namespace Microsoft.AspNetCore.ResponseCaching await _next(httpContext); // If there was no response body, check the response headers now. We can cache things like redirects. - OnResponseStarting(context); + await OnResponseStartingAsync(context); // Finalize the cache entry - FinalizeCacheBody(context); + await FinalizeCacheBodyAsync(context); } finally { @@ -135,7 +131,7 @@ namespace Microsoft.AspNetCore.ResponseCaching response.Headers[HeaderNames.Age] = context.CachedEntryAge.TotalSeconds.ToString("F0", CultureInfo.InvariantCulture); var body = context.CachedResponse.Body ?? - ((CachedResponseBody)_store.Get(context.CachedResponse.BodyKeyPrefix))?.Body; + ((CachedResponseBody) await _store.GetAsync(context.CachedResponse.BodyKeyPrefix))?.Body; // If the body is not found, something went wrong. if (body == null) @@ -164,7 +160,7 @@ namespace Microsoft.AspNetCore.ResponseCaching internal async Task TryServeFromCacheAsync(ResponseCacheContext context) { context.BaseKey = _keyProvider.CreateBaseKey(context); - var cacheEntry = _store.Get(context.BaseKey); + var cacheEntry = await _store.GetAsync(context.BaseKey); if (cacheEntry is CachedVaryByRules) { @@ -173,7 +169,7 @@ namespace Microsoft.AspNetCore.ResponseCaching foreach (var varyKey in _keyProvider.CreateLookupVaryByKeys(context)) { - cacheEntry = _store.Get(varyKey); + cacheEntry = await _store.GetAsync(varyKey); if (cacheEntry is CachedResponse && await TryServeCachedResponseAsync(context, (CachedResponse)cacheEntry)) { @@ -196,7 +192,7 @@ namespace Microsoft.AspNetCore.ResponseCaching return false; } - internal void FinalizeCacheHeaders(ResponseCacheContext context) + internal async Task FinalizeCacheHeadersAsync(ResponseCacheContext context) { if (_policyProvider.IsResponseCacheable(context)) { @@ -232,7 +228,7 @@ namespace Microsoft.AspNetCore.ResponseCaching } // Always overwrite the CachedVaryByRules to update the expiry information - _store.Set(context.BaseKey, context.CachedVaryByRules, context.CachedResponseValidFor); + await _store.SetAsync(context.BaseKey, context.CachedVaryByRules, context.CachedResponseValidFor); context.StorageVaryKey = _keyProvider.CreateStorageVaryByKey(context); } @@ -265,7 +261,7 @@ namespace Microsoft.AspNetCore.ResponseCaching } } - internal void FinalizeCacheBody(ResponseCacheContext context) + internal async Task FinalizeCacheBodyAsync(ResponseCacheContext context) { if (context.ShouldCacheResponse && context.ResponseCacheStream.BufferingEnabled && @@ -275,32 +271,36 @@ namespace Microsoft.AspNetCore.ResponseCaching if (context.ResponseCacheStream.BufferedStream.Length >= _options.MinimumSplitBodySize) { // Store response and response body separately - _store.Set(context.StorageVaryKey ?? context.BaseKey, context.CachedResponse, context.CachedResponseValidFor); + await _store.SetAsync(context.StorageVaryKey ?? context.BaseKey, context.CachedResponse, context.CachedResponseValidFor); var cachedResponseBody = new CachedResponseBody() { Body = context.ResponseCacheStream.BufferedStream.ToArray() }; - _store.Set(context.CachedResponse.BodyKeyPrefix, cachedResponseBody, context.CachedResponseValidFor); + await _store.SetAsync(context.CachedResponse.BodyKeyPrefix, cachedResponseBody, context.CachedResponseValidFor); } else { // Store response and response body together context.CachedResponse.Body = context.ResponseCacheStream.BufferedStream.ToArray(); - _store.Set(context.StorageVaryKey ?? context.BaseKey, context.CachedResponse, context.CachedResponseValidFor); + await _store.SetAsync(context.StorageVaryKey ?? context.BaseKey, context.CachedResponse, context.CachedResponseValidFor); } } } - internal void OnResponseStarting(ResponseCacheContext context) + internal Task OnResponseStartingAsync(ResponseCacheContext context) { if (!context.ResponseStarted) { context.ResponseStarted = true; context.ResponseTime = _options.SystemClock.UtcNow; - FinalizeCacheHeaders(context); + return FinalizeCacheHeadersAsync(context); + } + else + { + return TaskCache.CompletedTask; } } diff --git a/test/Microsoft.AspNetCore.ResponseCaching.Tests/ResponseCacheMiddlewareTests.cs b/test/Microsoft.AspNetCore.ResponseCaching.Tests/ResponseCacheMiddlewareTests.cs index 4b66d8b21b..d7db493fd9 100644 --- a/test/Microsoft.AspNetCore.ResponseCaching.Tests/ResponseCacheMiddlewareTests.cs +++ b/test/Microsoft.AspNetCore.ResponseCaching.Tests/ResponseCacheMiddlewareTests.cs @@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests var middleware = TestUtils.CreateTestMiddleware(store: store, keyProvider: new TestResponseCacheKeyProvider("BaseKey")); var context = TestUtils.CreateTestContext(); - store.Set( + await store.SetAsync( "BaseKey", new CachedResponse() { @@ -68,7 +68,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests var middleware = TestUtils.CreateTestMiddleware(store: store, keyProvider: new TestResponseCacheKeyProvider("BaseKey")); var context = TestUtils.CreateTestContext(); - store.Set( + await store.SetAsync( "BaseKey", new CachedVaryByRules(), TimeSpan.Zero); @@ -84,11 +84,11 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests var middleware = TestUtils.CreateTestMiddleware(store: store, keyProvider: new TestResponseCacheKeyProvider("BaseKey", new[] { "VaryKey", "VaryKey2" })); var context = TestUtils.CreateTestContext(); - store.Set( + await store.SetAsync( "BaseKey", new CachedVaryByRules(), TimeSpan.Zero); - store.Set( + await store.SetAsync( "BaseKeyVaryKey2", new CachedResponse() { @@ -226,7 +226,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests } [Fact] - public void FinalizeCacheHeaders_DoNotUpdateShouldCacheResponse_IfResponseIsNotCacheable() + public async Task FinalizeCacheHeaders_DoNotUpdateShouldCacheResponse_IfResponseIsNotCacheable() { var middleware = TestUtils.CreateTestMiddleware(policyProvider: new ResponseCachePolicyProvider()); var context = TestUtils.CreateTestContext(); @@ -234,13 +234,13 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests Assert.False(context.ShouldCacheResponse); middleware.ShimResponseStream(context); - middleware.FinalizeCacheHeaders(context); + await middleware.FinalizeCacheHeadersAsync(context); Assert.False(context.ShouldCacheResponse); } [Fact] - public void FinalizeCacheHeaders_UpdateShouldCacheResponse_IfResponseIsCacheable() + public async Task FinalizeCacheHeaders_UpdateShouldCacheResponse_IfResponseIsCacheable() { var middleware = TestUtils.CreateTestMiddleware(policyProvider: new ResponseCachePolicyProvider()); var context = TestUtils.CreateTestContext(); @@ -251,24 +251,24 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests Assert.False(context.ShouldCacheResponse); - middleware.FinalizeCacheHeaders(context); + await middleware.FinalizeCacheHeadersAsync(context); Assert.True(context.ShouldCacheResponse); } [Fact] - public void FinalizeCacheHeaders_DefaultResponseValidity_Is10Seconds() + public async Task FinalizeCacheHeaders_DefaultResponseValidity_Is10Seconds() { var middleware = TestUtils.CreateTestMiddleware(); var context = TestUtils.CreateTestContext(); - middleware.FinalizeCacheHeaders(context); + await middleware.FinalizeCacheHeadersAsync(context); Assert.Equal(TimeSpan.FromSeconds(10), context.CachedResponseValidFor); } [Fact] - public void FinalizeCacheHeaders_ResponseValidity_UseExpiryIfAvailable() + public async Task FinalizeCacheHeaders_ResponseValidity_UseExpiryIfAvailable() { var utcNow = DateTimeOffset.MinValue; var middleware = TestUtils.CreateTestMiddleware(); @@ -277,13 +277,13 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests context.ResponseTime = utcNow; context.TypedResponseHeaders.Expires = utcNow + TimeSpan.FromSeconds(11); - middleware.FinalizeCacheHeaders(context); + await middleware.FinalizeCacheHeadersAsync(context); Assert.Equal(TimeSpan.FromSeconds(11), context.CachedResponseValidFor); } [Fact] - public void FinalizeCacheHeaders_ResponseValidity_UseMaxAgeIfAvailable() + public async Task FinalizeCacheHeaders_ResponseValidity_UseMaxAgeIfAvailable() { var middleware = TestUtils.CreateTestMiddleware(); var context = TestUtils.CreateTestContext(); @@ -295,13 +295,13 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests context.ResponseTime = DateTimeOffset.UtcNow; context.TypedResponseHeaders.Expires = context.ResponseTime + TimeSpan.FromSeconds(11); - middleware.FinalizeCacheHeaders(context); + await middleware.FinalizeCacheHeadersAsync(context); Assert.Equal(TimeSpan.FromSeconds(12), context.CachedResponseValidFor); } [Fact] - public void FinalizeCacheHeaders_ResponseValidity_UseSharedMaxAgeIfAvailable() + public async Task FinalizeCacheHeaders_ResponseValidity_UseSharedMaxAgeIfAvailable() { var middleware = TestUtils.CreateTestMiddleware(); var context = TestUtils.CreateTestContext(); @@ -314,7 +314,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests context.ResponseTime = DateTimeOffset.UtcNow; context.TypedResponseHeaders.Expires = context.ResponseTime + TimeSpan.FromSeconds(11); - middleware.FinalizeCacheHeaders(context); + await middleware.FinalizeCacheHeadersAsync(context); Assert.Equal(TimeSpan.FromSeconds(13), context.CachedResponseValidFor); } @@ -337,7 +337,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests context.CachedVaryByRules = cachedVaryByRules; await middleware.TryServeFromCacheAsync(context); - middleware.FinalizeCacheHeaders(context); + await middleware.FinalizeCacheHeadersAsync(context); Assert.Equal(1, store.SetCount); Assert.NotSame(cachedVaryByRules, context.CachedVaryByRules); @@ -362,7 +362,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests context.CachedVaryByRules = cachedVaryByRules; await middleware.TryServeFromCacheAsync(context); - middleware.FinalizeCacheHeaders(context); + await middleware.FinalizeCacheHeadersAsync(context); // An update to the cache is always made but the entry should be the same Assert.Equal(1, store.SetCount); @@ -370,7 +370,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests } [Fact] - public void FinalizeCacheHeaders_DoNotAddDate_IfSpecified() + public async Task FinalizeCacheHeaders_DoNotAddDate_IfSpecified() { var utcNow = DateTimeOffset.MinValue; var middleware = TestUtils.CreateTestMiddleware(); @@ -379,13 +379,13 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests Assert.Null(context.TypedResponseHeaders.Date); - middleware.FinalizeCacheHeaders(context); + await middleware.FinalizeCacheHeadersAsync(context); Assert.Equal(utcNow, context.TypedResponseHeaders.Date); } [Fact] - public void FinalizeCacheHeaders_AddsDate_IfNoneSpecified() + public async Task FinalizeCacheHeaders_AddsDate_IfNoneSpecified() { var utcNow = DateTimeOffset.MinValue; var middleware = TestUtils.CreateTestMiddleware(); @@ -395,20 +395,20 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests Assert.Equal(utcNow, context.TypedResponseHeaders.Date); - middleware.FinalizeCacheHeaders(context); + await middleware.FinalizeCacheHeadersAsync(context); Assert.Equal(utcNow, context.TypedResponseHeaders.Date); } [Fact] - public void FinalizeCacheHeaders_StoresCachedResponse_InState() + public async Task FinalizeCacheHeaders_StoresCachedResponse_InState() { var middleware = TestUtils.CreateTestMiddleware(); var context = TestUtils.CreateTestContext(); Assert.Null(context.CachedResponse); - middleware.FinalizeCacheHeaders(context); + await middleware.FinalizeCacheHeadersAsync(context); Assert.NotNull(context.CachedResponse); } @@ -421,7 +421,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests context.HttpContext.Response.Headers[HeaderNames.Vary] = "HeaderB, heaDera"; await middleware.TryServeFromCacheAsync(context); - middleware.FinalizeCacheHeaders(context); + await middleware.FinalizeCacheHeadersAsync(context); Assert.Equal(new StringValues(new[] { "HEADERA", "HEADERB" }), context.CachedVaryByRules.Headers); } @@ -444,7 +444,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests context.BaseKey = "BaseKey"; context.CachedResponseValidFor = TimeSpan.FromSeconds(10); - middleware.FinalizeCacheBody(context); + await middleware.FinalizeCacheBodyAsync(context); Assert.Equal(2, store.SetCount); } @@ -467,7 +467,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests context.BaseKey = "BaseKey"; context.CachedResponseValidFor = TimeSpan.FromSeconds(10); - middleware.FinalizeCacheBody(context); + await middleware.FinalizeCacheBodyAsync(context); Assert.Equal(1, store.SetCount); } @@ -493,7 +493,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests context.BaseKey = "BaseKey"; context.CachedResponseValidFor = TimeSpan.FromSeconds(10); - middleware.FinalizeCacheBody(context); + await middleware.FinalizeCacheBodyAsync(context); Assert.Equal(1, store.SetCount); } @@ -517,7 +517,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests context.BaseKey = "BaseKey"; context.CachedResponseValidFor = TimeSpan.FromSeconds(10); - middleware.FinalizeCacheBody(context); + await middleware.FinalizeCacheBodyAsync(context); Assert.Equal(1, store.SetCount); } @@ -541,7 +541,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests context.BaseKey = "BaseKey"; context.CachedResponseValidFor = TimeSpan.FromSeconds(10); - middleware.FinalizeCacheBody(context); + await middleware.FinalizeCacheBodyAsync(context); Assert.Equal(0, store.SetCount); } @@ -564,7 +564,7 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests context.BaseKey = "BaseKey"; context.CachedResponseValidFor = TimeSpan.FromSeconds(10); - middleware.FinalizeCacheBody(context); + await middleware.FinalizeCacheBodyAsync(context); Assert.Equal(1, store.SetCount); } diff --git a/test/Microsoft.AspNetCore.ResponseCaching.Tests/TestUtils.cs b/test/Microsoft.AspNetCore.ResponseCaching.Tests/TestUtils.cs index 96d45f71d2..3ccb72fe0c 100644 --- a/test/Microsoft.AspNetCore.ResponseCaching.Tests/TestUtils.cs +++ b/test/Microsoft.AspNetCore.ResponseCaching.Tests/TestUtils.cs @@ -168,27 +168,29 @@ namespace Microsoft.AspNetCore.ResponseCaching.Tests public int GetCount { get; private set; } public int SetCount { get; private set; } - public object Get(string key) + public Task GetAsync(string key) { GetCount++; try { - return _storage[key]; + return Task.FromResult(_storage[key]); } catch { - return null; + return Task.FromResult(null); } } - public void Remove(string key) + public Task RemoveAsync(string key) { + return TaskCache.CompletedTask; } - public void Set(string key, object entry, TimeSpan validFor) + public Task SetAsync(string key, object entry, TimeSpan validFor) { SetCount++; _storage[key] = entry; + return TaskCache.CompletedTask; } } }