Reacting to changes in Caching
This commit is contained in:
parent
66ff9939c3
commit
476d2eb81d
|
|
@ -82,22 +82,28 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var tcs = new TaskCompletionSource<IHtmlContent>();
|
||||
|
||||
MemoryCache.Set(key, tcs.Task, options);
|
||||
// The returned value is ignored, we only do this so that
|
||||
// the compiler doesn't complain about the returned task
|
||||
// not being awaited
|
||||
var localTcs = MemoryCache.Set(key, tcs.Task, options);
|
||||
|
||||
try
|
||||
{
|
||||
using (var link = MemoryCache.CreateLinkingScope())
|
||||
{
|
||||
result = ProcessContentAsync(output);
|
||||
content = await result;
|
||||
options.AddEntryLink(link);
|
||||
}
|
||||
|
||||
// The entry is set instead of assigning a value to the
|
||||
// task so that the expiration options are are not impacted
|
||||
// by the time it took to compute it.
|
||||
|
||||
MemoryCache.Set(key, result, options);
|
||||
|
||||
using (var entry = MemoryCache.CreateEntry(key))
|
||||
{
|
||||
// The result is processed inside an entry
|
||||
// such that the tokens are inherited.
|
||||
|
||||
result = ProcessContentAsync(output);
|
||||
content = await result;
|
||||
|
||||
entry.SetOptions(options);
|
||||
entry.Value = result;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System.Linq;
|
|||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Html;
|
||||
|
|
@ -250,12 +251,12 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
var id = "unique-id";
|
||||
var childContent = "original-child-content";
|
||||
var cache = new Mock<IMemoryCache>();
|
||||
var value = new DefaultTagHelperContent().SetContent("ok");
|
||||
cache.Setup(c => c.Set(
|
||||
/*key*/ It.IsAny<string>(),
|
||||
/*value*/ value,
|
||||
/*optons*/ It.IsAny<MemoryCacheEntryOptions>()))
|
||||
.Returns(value);
|
||||
var value = new Mock<ICacheEntry>();
|
||||
value.Setup(c => c.Value).Returns(new DefaultTagHelperContent().SetContent("ok"));
|
||||
cache.Setup(c => c.CreateEntry(
|
||||
/*key*/ It.IsAny<string>()))
|
||||
.Returns((object key) => value.Object)
|
||||
.Verifiable();
|
||||
object cacheResult;
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out cacheResult))
|
||||
.Returns(false);
|
||||
|
|
@ -274,10 +275,8 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
// Assert
|
||||
Assert.Equal(childContent, tagHelperOutput.Content.GetContent());
|
||||
cache.Verify(c => c.Set(
|
||||
/*key*/ It.IsAny<string>(),
|
||||
/*value*/ It.IsAny<object>(),
|
||||
/*options*/ It.IsAny<MemoryCacheEntryOptions>()),
|
||||
cache.Verify(c => c.CreateEntry(
|
||||
/*key*/ It.IsAny<string>()),
|
||||
Times.Never);
|
||||
}
|
||||
|
||||
|
|
@ -288,13 +287,12 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
var id = "unique-id";
|
||||
var childContent = "original-child-content";
|
||||
var cache = new Mock<IMemoryCache>();
|
||||
var value = new DefaultTagHelperContent().SetContent("ok");
|
||||
cache.Setup(c => c.CreateLinkingScope()).Returns(new Mock<IEntryLink>().Object);
|
||||
cache.Setup(c => c.Set(
|
||||
/*key*/ It.IsAny<string>(),
|
||||
/*value*/ It.IsAny<object>(),
|
||||
/*options*/ It.IsAny<MemoryCacheEntryOptions>()))
|
||||
.Returns(value);
|
||||
var value = new Mock<ICacheEntry>();
|
||||
value.Setup(c => c.Value).Returns(new DefaultTagHelperContent().SetContent("ok"));
|
||||
value.Setup(c => c.ExpirationTokens).Returns(new List<IChangeToken>());
|
||||
cache.Setup(c => c.CreateEntry(
|
||||
/*key*/ It.IsAny<string>()))
|
||||
.Returns((object key) => value.Object);
|
||||
object cacheResult;
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out cacheResult))
|
||||
.Returns(false);
|
||||
|
|
@ -318,10 +316,8 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
Assert.Equal(childContent, tagHelperOutput.Content.GetContent());
|
||||
|
||||
// There are two calls to set (for the TCS and the processed value)
|
||||
cache.Verify(c => c.Set(
|
||||
/*key*/ It.IsAny<string>(),
|
||||
/*value*/ It.IsAny<object>(),
|
||||
/*options*/ It.IsAny<MemoryCacheEntryOptions>()),
|
||||
cache.Verify(c => c.CreateEntry(
|
||||
/*key*/ It.IsAny<string>()),
|
||||
Times.Exactly(2));
|
||||
}
|
||||
|
||||
|
|
@ -443,51 +439,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
// Assert
|
||||
Assert.Equal(expiresOn, cacheEntryOptions.AbsoluteExpiration);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateCacheEntryOptions_UsesAbsoluteExpirationSpecifiedOnEntryLink()
|
||||
{
|
||||
// Arrange
|
||||
var expiresOn = DateTimeOffset.UtcNow.AddMinutes(7);
|
||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
};
|
||||
|
||||
var entryLink = new EntryLink();
|
||||
entryLink.SetAbsoluteExpiration(expiresOn);
|
||||
|
||||
// Act
|
||||
var cacheEntryOptions = cacheTagHelper.GetMemoryCacheEntryOptions();
|
||||
cacheEntryOptions.AddEntryLink(entryLink);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expiresOn, cacheEntryOptions.AbsoluteExpiration);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateCacheEntryOptions_PrefersAbsoluteExpirationSpecifiedOnEntryLinkOverExpiresOn()
|
||||
{
|
||||
// Arrange
|
||||
var expiresOn1 = DateTimeOffset.UtcNow.AddDays(12);
|
||||
var expiresOn2 = DateTimeOffset.UtcNow.AddMinutes(4);
|
||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
ExpiresOn = expiresOn1
|
||||
};
|
||||
|
||||
var entryLink = new EntryLink();
|
||||
entryLink.SetAbsoluteExpiration(expiresOn2);
|
||||
|
||||
// Act
|
||||
var cacheEntryOptions = cacheTagHelper.GetMemoryCacheEntryOptions();
|
||||
cacheEntryOptions.AddEntryLink(entryLink);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expiresOn2, cacheEntryOptions.AbsoluteExpiration);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void UpdateCacheEntryOptions_SetsAbsoluteExpiration_IfExpiresAfterIsSet()
|
||||
{
|
||||
|
|
@ -541,30 +493,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
// Assert
|
||||
Assert.Equal(priority, cacheEntryOptions.Priority);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateCacheEntryOptions_CopiesTriggersFromEntryLink()
|
||||
{
|
||||
// Arrange
|
||||
var expiresSliding = TimeSpan.FromSeconds(30);
|
||||
var expected = new[] { Mock.Of<IChangeToken>(), Mock.Of<IChangeToken>() };
|
||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||
var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder())
|
||||
{
|
||||
ExpiresSliding = expiresSliding
|
||||
};
|
||||
|
||||
var entryLink = new EntryLink();
|
||||
entryLink.AddExpirationTokens(expected);
|
||||
|
||||
// Act
|
||||
var cacheEntryOptions = cacheTagHelper.GetMemoryCacheEntryOptions();
|
||||
cacheEntryOptions.AddEntryLink(entryLink);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, cacheEntryOptions.ExpirationTokens.ToArray());
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public async Task ProcessAsync_UsesExpiresAfter_ToExpireCacheEntry()
|
||||
{
|
||||
|
|
@ -961,6 +890,17 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
});
|
||||
}
|
||||
|
||||
private static TagHelperOutput GetTagHelperOutput(
|
||||
Func<bool, HtmlEncoder, Task<TagHelperContent>> processAsync)
|
||||
{
|
||||
var attributes = new TagHelperAttributeList { { "attr", "value" } };
|
||||
|
||||
return new TagHelperOutput(
|
||||
"cache",
|
||||
attributes,
|
||||
getChildContentAsync: processAsync);
|
||||
}
|
||||
|
||||
private static string GetHashedBytes(string input)
|
||||
{
|
||||
using (var sha = SHA256.Create())
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
|
@ -278,15 +279,16 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal
|
|||
.Setup(f => f.Watch(watchPath)).Returns(changeToken.Object);
|
||||
|
||||
object cacheValue = null;
|
||||
var value = new Mock<ICacheEntry>();
|
||||
value.Setup(c => c.Value).Returns(cacheValue);
|
||||
value.Setup(c => c.ExpirationTokens).Returns(new List<IChangeToken>());
|
||||
var cache = new Mock<IMemoryCache>();
|
||||
cache.CallBase = true;
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out cacheValue))
|
||||
.Returns(cacheValue != null);
|
||||
cache.Setup(c => c.Set(
|
||||
/*key*/ filePath,
|
||||
/*value*/ It.IsAny<object>(),
|
||||
/*options*/ It.IsAny<MemoryCacheEntryOptions>()))
|
||||
.Returns((object key, object value, MemoryCacheEntryOptions options) => value)
|
||||
cache.Setup(c => c.CreateEntry(
|
||||
/*key*/ filePath))
|
||||
.Returns((object key) => value.Object)
|
||||
.Verifiable();
|
||||
var fileVersionProvider = new FileVersionProvider(
|
||||
fileProvider,
|
||||
|
|
|
|||
|
|
@ -275,12 +275,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal
|
|||
var changeToken = new Mock<IChangeToken>();
|
||||
var fileProvider = MakeFileProvider(MakeDirectoryContents("site.css", "blank.css"));
|
||||
Mock.Get(fileProvider).Setup(f => f.Watch(It.IsAny<string>())).Returns(changeToken.Object);
|
||||
var value = new Mock<ICacheEntry>();
|
||||
value.Setup(c => c.Value).Returns(null);
|
||||
value.Setup(c => c.ExpirationTokens).Returns(new List<IChangeToken>());
|
||||
var cache = MakeCache();
|
||||
Mock.Get(cache).Setup(c => c.Set(
|
||||
/*key*/ It.IsAny<object>(),
|
||||
/*value*/ It.IsAny<List<string>>(),
|
||||
/*options*/ It.IsAny<MemoryCacheEntryOptions>()))
|
||||
.Returns((object key, object value, MemoryCacheEntryOptions options) => value)
|
||||
Mock.Get(cache).Setup(c => c.CreateEntry(
|
||||
/*key*/ It.IsAny<object>()))
|
||||
.Returns((object key) => value.Object)
|
||||
.Verifiable();
|
||||
var requestPathBase = PathString.Empty;
|
||||
var globbingUrlBuilder = new GlobbingUrlBuilder(fileProvider, cache, requestPathBase);
|
||||
|
|
|
|||
Loading…
Reference in New Issue