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

Commit 476d2eb

Browse files
committed
Reacting to changes in Caching
1 parent 66ff993 commit 476d2eb

File tree

4 files changed

+58
-109
lines changed

4 files changed

+58
-109
lines changed

src/Microsoft.AspNetCore.Mvc.TagHelpers/CacheTagHelper.cs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,22 +82,28 @@ public override async Task ProcessAsync(TagHelperContext context, TagHelperOutpu
8282

8383
var tcs = new TaskCompletionSource<IHtmlContent>();
8484

85-
MemoryCache.Set(key, tcs.Task, options);
85+
// The returned value is ignored, we only do this so that
86+
// the compiler doesn't complain about the returned task
87+
// not being awaited
88+
var localTcs = MemoryCache.Set(key, tcs.Task, options);
8689

8790
try
8891
{
89-
using (var link = MemoryCache.CreateLinkingScope())
92+
// The entry is set instead of assigning a value to the
93+
// task so that the expiration options are are not impacted
94+
// by the time it took to compute it.
95+
96+
using (var entry = MemoryCache.CreateEntry(key))
9097
{
98+
// The result is processed inside an entry
99+
// such that the tokens are inherited.
100+
91101
result = ProcessContentAsync(output);
92102
content = await result;
93-
options.AddEntryLink(link);
103+
104+
entry.SetOptions(options);
105+
entry.Value = result;
94106
}
95-
96-
// The entry is set instead of assigning a value to the
97-
// task so that the expiration options are are not impacted
98-
// by the time it took to compute it.
99-
100-
MemoryCache.Set(key, result, options);
101107
}
102108
catch
103109
{

test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/CacheTagHelperTest.cs

Lines changed: 30 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Security.Claims;
99
using System.Security.Cryptography;
1010
using System.Text;
11+
using System.Text.Encodings.Web;
1112
using System.Threading;
1213
using System.Threading.Tasks;
1314
using Microsoft.AspNetCore.Html;
@@ -250,12 +251,12 @@ public async Task ProcessAsync_DoesNotCache_IfDisabled()
250251
var id = "unique-id";
251252
var childContent = "original-child-content";
252253
var cache = new Mock<IMemoryCache>();
253-
var value = new DefaultTagHelperContent().SetContent("ok");
254-
cache.Setup(c => c.Set(
255-
/*key*/ It.IsAny<string>(),
256-
/*value*/ value,
257-
/*optons*/ It.IsAny<MemoryCacheEntryOptions>()))
258-
.Returns(value);
254+
var value = new Mock<ICacheEntry>();
255+
value.Setup(c => c.Value).Returns(new DefaultTagHelperContent().SetContent("ok"));
256+
cache.Setup(c => c.CreateEntry(
257+
/*key*/ It.IsAny<string>()))
258+
.Returns((object key) => value.Object)
259+
.Verifiable();
259260
object cacheResult;
260261
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out cacheResult))
261262
.Returns(false);
@@ -274,10 +275,8 @@ public async Task ProcessAsync_DoesNotCache_IfDisabled()
274275

275276
// Assert
276277
Assert.Equal(childContent, tagHelperOutput.Content.GetContent());
277-
cache.Verify(c => c.Set(
278-
/*key*/ It.IsAny<string>(),
279-
/*value*/ It.IsAny<object>(),
280-
/*options*/ It.IsAny<MemoryCacheEntryOptions>()),
278+
cache.Verify(c => c.CreateEntry(
279+
/*key*/ It.IsAny<string>()),
281280
Times.Never);
282281
}
283282

@@ -288,13 +287,12 @@ public async Task ProcessAsync_ReturnsCachedValue_IfEnabled()
288287
var id = "unique-id";
289288
var childContent = "original-child-content";
290289
var cache = new Mock<IMemoryCache>();
291-
var value = new DefaultTagHelperContent().SetContent("ok");
292-
cache.Setup(c => c.CreateLinkingScope()).Returns(new Mock<IEntryLink>().Object);
293-
cache.Setup(c => c.Set(
294-
/*key*/ It.IsAny<string>(),
295-
/*value*/ It.IsAny<object>(),
296-
/*options*/ It.IsAny<MemoryCacheEntryOptions>()))
297-
.Returns(value);
290+
var value = new Mock<ICacheEntry>();
291+
value.Setup(c => c.Value).Returns(new DefaultTagHelperContent().SetContent("ok"));
292+
value.Setup(c => c.ExpirationTokens).Returns(new List<IChangeToken>());
293+
cache.Setup(c => c.CreateEntry(
294+
/*key*/ It.IsAny<string>()))
295+
.Returns((object key) => value.Object);
298296
object cacheResult;
299297
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out cacheResult))
300298
.Returns(false);
@@ -318,10 +316,8 @@ public async Task ProcessAsync_ReturnsCachedValue_IfEnabled()
318316
Assert.Equal(childContent, tagHelperOutput.Content.GetContent());
319317

320318
// There are two calls to set (for the TCS and the processed value)
321-
cache.Verify(c => c.Set(
322-
/*key*/ It.IsAny<string>(),
323-
/*value*/ It.IsAny<object>(),
324-
/*options*/ It.IsAny<MemoryCacheEntryOptions>()),
319+
cache.Verify(c => c.CreateEntry(
320+
/*key*/ It.IsAny<string>()),
325321
Times.Exactly(2));
326322
}
327323

@@ -443,51 +439,7 @@ public void UpdateCacheEntryOptions_SetsAbsoluteExpiration_IfExpiresOnIsSet()
443439
// Assert
444440
Assert.Equal(expiresOn, cacheEntryOptions.AbsoluteExpiration);
445441
}
446-
447-
[Fact]
448-
public void UpdateCacheEntryOptions_UsesAbsoluteExpirationSpecifiedOnEntryLink()
449-
{
450-
// Arrange
451-
var expiresOn = DateTimeOffset.UtcNow.AddMinutes(7);
452-
var cache = new MemoryCache(new MemoryCacheOptions());
453-
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
454-
{
455-
};
456-
457-
var entryLink = new EntryLink();
458-
entryLink.SetAbsoluteExpiration(expiresOn);
459-
460-
// Act
461-
var cacheEntryOptions = cacheTagHelper.GetMemoryCacheEntryOptions();
462-
cacheEntryOptions.AddEntryLink(entryLink);
463-
464-
// Assert
465-
Assert.Equal(expiresOn, cacheEntryOptions.AbsoluteExpiration);
466-
}
467-
468-
[Fact]
469-
public void UpdateCacheEntryOptions_PrefersAbsoluteExpirationSpecifiedOnEntryLinkOverExpiresOn()
470-
{
471-
// Arrange
472-
var expiresOn1 = DateTimeOffset.UtcNow.AddDays(12);
473-
var expiresOn2 = DateTimeOffset.UtcNow.AddMinutes(4);
474-
var cache = new MemoryCache(new MemoryCacheOptions());
475-
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
476-
{
477-
ExpiresOn = expiresOn1
478-
};
479-
480-
var entryLink = new EntryLink();
481-
entryLink.SetAbsoluteExpiration(expiresOn2);
482-
483-
// Act
484-
var cacheEntryOptions = cacheTagHelper.GetMemoryCacheEntryOptions();
485-
cacheEntryOptions.AddEntryLink(entryLink);
486-
487-
// Assert
488-
Assert.Equal(expiresOn2, cacheEntryOptions.AbsoluteExpiration);
489-
}
490-
442+
491443
[Fact]
492444
public void UpdateCacheEntryOptions_SetsAbsoluteExpiration_IfExpiresAfterIsSet()
493445
{
@@ -541,30 +493,7 @@ public void UpdateCacheEntryOptions_SetsCachePreservationPriority()
541493
// Assert
542494
Assert.Equal(priority, cacheEntryOptions.Priority);
543495
}
544-
545-
[Fact]
546-
public void UpdateCacheEntryOptions_CopiesTriggersFromEntryLink()
547-
{
548-
// Arrange
549-
var expiresSliding = TimeSpan.FromSeconds(30);
550-
var expected = new[] { Mock.Of<IChangeToken>(), Mock.Of<IChangeToken>() };
551-
var cache = new MemoryCache(new MemoryCacheOptions());
552-
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
553-
{
554-
ExpiresSliding = expiresSliding
555-
};
556-
557-
var entryLink = new EntryLink();
558-
entryLink.AddExpirationTokens(expected);
559-
560-
// Act
561-
var cacheEntryOptions = cacheTagHelper.GetMemoryCacheEntryOptions();
562-
cacheEntryOptions.AddEntryLink(entryLink);
563-
564-
// Assert
565-
Assert.Equal(expected, cacheEntryOptions.ExpirationTokens.ToArray());
566-
}
567-
496+
568497
[Fact]
569498
public async Task ProcessAsync_UsesExpiresAfter_ToExpireCacheEntry()
570499
{
@@ -961,6 +890,17 @@ private static TagHelperOutput GetTagHelperOutput(
961890
});
962891
}
963892

893+
private static TagHelperOutput GetTagHelperOutput(
894+
Func<bool, HtmlEncoder, Task<TagHelperContent>> processAsync)
895+
{
896+
var attributes = new TagHelperAttributeList { { "attr", "value" } };
897+
898+
return new TagHelperOutput(
899+
"cache",
900+
attributes,
901+
getChildContentAsync: processAsync);
902+
}
903+
964904
private static string GetHashedBytes(string input)
965905
{
966906
using (var sha = SHA256.Create())

test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/FileVersionProviderTest.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System.Collections.Generic;
45
using System.IO;
56
using System.Text;
67
using Microsoft.AspNetCore.Http;
@@ -278,15 +279,16 @@ public void SetsValueInCache(string filePath, string watchPath, string requestPa
278279
.Setup(f => f.Watch(watchPath)).Returns(changeToken.Object);
279280

280281
object cacheValue = null;
282+
var value = new Mock<ICacheEntry>();
283+
value.Setup(c => c.Value).Returns(cacheValue);
284+
value.Setup(c => c.ExpirationTokens).Returns(new List<IChangeToken>());
281285
var cache = new Mock<IMemoryCache>();
282286
cache.CallBase = true;
283287
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out cacheValue))
284288
.Returns(cacheValue != null);
285-
cache.Setup(c => c.Set(
286-
/*key*/ filePath,
287-
/*value*/ It.IsAny<object>(),
288-
/*options*/ It.IsAny<MemoryCacheEntryOptions>()))
289-
.Returns((object key, object value, MemoryCacheEntryOptions options) => value)
289+
cache.Setup(c => c.CreateEntry(
290+
/*key*/ filePath))
291+
.Returns((object key) => value.Object)
290292
.Verifiable();
291293
var fileVersionProvider = new FileVersionProvider(
292294
fileProvider,

test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/GlobbingUrlBuilderTest.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -275,12 +275,13 @@ public void CachesMatchResults()
275275
var changeToken = new Mock<IChangeToken>();
276276
var fileProvider = MakeFileProvider(MakeDirectoryContents("site.css", "blank.css"));
277277
Mock.Get(fileProvider).Setup(f => f.Watch(It.IsAny<string>())).Returns(changeToken.Object);
278+
var value = new Mock<ICacheEntry>();
279+
value.Setup(c => c.Value).Returns(null);
280+
value.Setup(c => c.ExpirationTokens).Returns(new List<IChangeToken>());
278281
var cache = MakeCache();
279-
Mock.Get(cache).Setup(c => c.Set(
280-
/*key*/ It.IsAny<object>(),
281-
/*value*/ It.IsAny<List<string>>(),
282-
/*options*/ It.IsAny<MemoryCacheEntryOptions>()))
283-
.Returns((object key, object value, MemoryCacheEntryOptions options) => value)
282+
Mock.Get(cache).Setup(c => c.CreateEntry(
283+
/*key*/ It.IsAny<object>()))
284+
.Returns((object key) => value.Object)
284285
.Verifiable();
285286
var requestPathBase = PathString.Empty;
286287
var globbingUrlBuilder = new GlobbingUrlBuilder(fileProvider, cache, requestPathBase);

0 commit comments

Comments
 (0)