React to Caching api review changes
This commit is contained in:
parent
8a701726b3
commit
2a321fd622
|
|
@ -1,9 +1,11 @@
|
|||
// 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 Microsoft.AspNet.Mvc;
|
||||
using Microsoft.Framework.Caching;
|
||||
using Microsoft.Framework.Caching.Memory;
|
||||
using TagHelperSample.Web.Models;
|
||||
using TagHelperSample.Web.Services;
|
||||
|
||||
namespace TagHelperSample.Web.Components
|
||||
|
|
@ -11,31 +13,41 @@ namespace TagHelperSample.Web.Components
|
|||
[ViewComponent(Name = "FeaturedMovies")]
|
||||
public class FeaturedMoviesComponent : ViewComponent
|
||||
{
|
||||
private MoviesService _moviesService;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly MoviesService _moviesService;
|
||||
|
||||
public FeaturedMoviesComponent(MoviesService moviesService)
|
||||
public FeaturedMoviesComponent(MoviesService moviesService, IMemoryCache cache)
|
||||
{
|
||||
_moviesService = moviesService;
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
public IViewComponentResult Invoke()
|
||||
{
|
||||
IExpirationTrigger trigger;
|
||||
var movies = _moviesService.GetFeaturedMovies(out trigger);
|
||||
|
||||
// Add custom triggers
|
||||
EntryLinkHelpers.ContextLink.AddExpirationTriggers(new[] { trigger });
|
||||
// Since this component is invoked from within a CacheTagHelper,
|
||||
// cache the movie list and provide an expiration trigger, which when triggered causes the
|
||||
// CacheTagHelper's cached data to be invalidated.
|
||||
var cacheKey = "featured_movies";
|
||||
IEnumerable<FeaturedMovies> movies;
|
||||
if (!_cache.TryGetValue(cacheKey, out movies))
|
||||
{
|
||||
IExpirationTrigger trigger;
|
||||
movies = _moviesService.GetFeaturedMovies(out trigger);
|
||||
_cache.Set(cacheKey, movies, new MemoryCacheEntryOptions().AddExpirationTrigger(trigger));
|
||||
}
|
||||
|
||||
return View(movies);
|
||||
}
|
||||
|
||||
public IViewComponentResult Invoke(string movieName)
|
||||
{
|
||||
IExpirationTrigger trigger;
|
||||
var quote = _moviesService.GetCriticsQuote(out trigger);
|
||||
|
||||
// This is invoked as part of a nested cache tag helper.
|
||||
EntryLinkHelpers.ContextLink.AddExpirationTriggers(new[] { trigger });
|
||||
string quote;
|
||||
if (!_cache.TryGetValue(movieName, out quote))
|
||||
{
|
||||
IExpirationTrigger trigger;
|
||||
quote = _moviesService.GetCriticsQuote(out trigger);
|
||||
_cache.Set(movieName, quote, new MemoryCacheEntryOptions().AddExpirationTrigger(trigger));
|
||||
}
|
||||
|
||||
return Content(quote);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
</div>
|
||||
<div class="sidebar">
|
||||
<cache expires-after="TimeSpan.FromMinutes(20)">
|
||||
@await Component.InvokeAsync("FeaturedMovies")
|
||||
@Component.Invoke("FeaturedMovies")
|
||||
</cache>
|
||||
</div>
|
||||
<div style="clear: left"></div>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
|
|||
{
|
||||
private static readonly MemoryCacheOptions MemoryCacheOptions = new MemoryCacheOptions
|
||||
{
|
||||
ListenForMemoryPressure = false
|
||||
CompactOnMemoryPressure = false
|
||||
};
|
||||
private static readonly TimeSpan SlidingExpirationDuration = TimeSpan.FromMinutes(1);
|
||||
private readonly IFileProvider _fileProvider;
|
||||
|
|
@ -43,22 +43,25 @@ namespace Microsoft.AspNet.Mvc.Razor.Directives
|
|||
public CodeTree GetOrAdd([NotNull] string pagePath,
|
||||
[NotNull] Func<IFileInfo, CodeTree> getCodeTree)
|
||||
{
|
||||
return _codeTreeCache.GetOrSet(pagePath, getCodeTree, OnCacheMiss);
|
||||
}
|
||||
CodeTree codeTree;
|
||||
if (!_codeTreeCache.TryGetValue(pagePath, out codeTree))
|
||||
{
|
||||
// GetOrAdd is invoked for each _GlobalImport that might potentially exist in the path.
|
||||
// We can avoid performing file system lookups for files that do not exist by caching
|
||||
// negative results and adding a Watch for that file.
|
||||
|
||||
private CodeTree OnCacheMiss(ICacheSetContext cacheSetContext)
|
||||
{
|
||||
var pagePath = cacheSetContext.Key;
|
||||
var getCodeTree = (Func<IFileInfo, CodeTree>)cacheSetContext.State;
|
||||
var options = new MemoryCacheEntryOptions()
|
||||
.AddExpirationTrigger(_fileProvider.Watch(pagePath))
|
||||
.SetSlidingExpiration(SlidingExpirationDuration);
|
||||
|
||||
// GetOrAdd is invoked for each _ViewImports that might potentially exist in the path.
|
||||
// We can avoid performing file system lookups for files that do not exist by caching
|
||||
// negative results and adding a Watch for that file.
|
||||
cacheSetContext.AddExpirationTrigger(_fileProvider.Watch(pagePath));
|
||||
cacheSetContext.SetSlidingExpiration(SlidingExpirationDuration);
|
||||
var file = _fileProvider.GetFileInfo(pagePath);
|
||||
codeTree = file.Exists ? getCodeTree(file) : null;
|
||||
|
||||
var file = _fileProvider.GetFileInfo(pagePath);
|
||||
return file.Exists ? getCodeTree(file) : null;
|
||||
|
||||
_codeTreeCache.Set(pagePath, codeTree, options);
|
||||
}
|
||||
|
||||
return codeTree;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -45,7 +45,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
|||
IFileProvider fileProvider)
|
||||
{
|
||||
_fileProvider = fileProvider;
|
||||
_cache = new MemoryCache(new MemoryCacheOptions { ListenForMemoryPressure = false });
|
||||
_cache = new MemoryCache(new MemoryCacheOptions { CompactOnMemoryPressure = false });
|
||||
|
||||
var cacheEntries = new List<CompilerCacheEntry>();
|
||||
foreach (var viewCollection in razorFileInfoCollections)
|
||||
|
|
@ -58,7 +58,11 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
|||
|
||||
// There shouldn't be any duplicates and if there are any the first will win.
|
||||
// If the result doesn't match the one on disk its going to recompile anyways.
|
||||
_cache.Set(NormalizePath(fileInfo.RelativePath), cacheEntry, PopulateCacheSetContext);
|
||||
var normalizedPath = NormalizePath(fileInfo.RelativePath);
|
||||
_cache.Set(
|
||||
normalizedPath,
|
||||
cacheEntry,
|
||||
GetMemoryCacheEntryOptions(fileInfo.RelativePath));
|
||||
|
||||
cacheEntries.Add(cacheEntry);
|
||||
}
|
||||
|
|
@ -184,9 +188,12 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
|||
var compilationResult = compile(file).EnsureSuccessful();
|
||||
|
||||
// Concurrent addition to MemoryCache with the same key result in safe race.
|
||||
var cacheEntry = _cache.Set(normalizedPath,
|
||||
new CompilerCacheEntry(file, compilationResult.CompiledType),
|
||||
PopulateCacheSetContext);
|
||||
var compilerCacheEntry = new CompilerCacheEntry(file, compilationResult.CompiledType);
|
||||
var cacheEntry = _cache.Set<CompilerCacheEntry>(
|
||||
normalizedPath,
|
||||
compilerCacheEntry,
|
||||
GetMemoryCacheEntryOptions(compilerCacheEntry.RelativePath));
|
||||
|
||||
return new GetOrAddResult
|
||||
{
|
||||
CompilationResult = compilationResult,
|
||||
|
|
@ -194,18 +201,17 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
|||
};
|
||||
}
|
||||
|
||||
private CompilerCacheEntry PopulateCacheSetContext(ICacheSetContext cacheSetContext)
|
||||
private MemoryCacheEntryOptions GetMemoryCacheEntryOptions(string relativePath)
|
||||
{
|
||||
var entry = (CompilerCacheEntry)cacheSetContext.State;
|
||||
cacheSetContext.AddExpirationTrigger(_fileProvider.Watch(entry.RelativePath));
|
||||
var options = new MemoryCacheEntryOptions();
|
||||
options.AddExpirationTrigger(_fileProvider.Watch(relativePath));
|
||||
|
||||
var viewImportsPaths = ViewHierarchyUtility.GetViewImportsLocations(cacheSetContext.Key);
|
||||
var viewImportsPaths = ViewHierarchyUtility.GetViewImportsLocations(relativePath);
|
||||
foreach (var location in viewImportsPaths)
|
||||
{
|
||||
cacheSetContext.AddExpirationTrigger(_fileProvider.Watch(location));
|
||||
options.AddExpirationTrigger(_fileProvider.Watch(location));
|
||||
}
|
||||
|
||||
return entry;
|
||||
return options;
|
||||
}
|
||||
|
||||
private bool AssociatedGlobalFilesChanged(CompilerCacheEntry entry,
|
||||
|
|
|
|||
|
|
@ -91,9 +91,17 @@ namespace Microsoft.AspNet.Mvc.Razor.Precompilation
|
|||
Parallel.For(0, filesToProcess.Count, parallelOptions, index =>
|
||||
{
|
||||
var file = filesToProcess[index];
|
||||
var cacheEntry = PreCompilationCache.GetOrSet(file.RelativePath,
|
||||
file,
|
||||
OnCacheMiss);
|
||||
|
||||
PrecompilationCacheEntry cacheEntry;
|
||||
if(!PreCompilationCache.TryGetValue(file.RelativePath, out cacheEntry))
|
||||
{
|
||||
cacheEntry = GetCacheEntry(file);
|
||||
PreCompilationCache.Set(
|
||||
file.RelativePath,
|
||||
cacheEntry,
|
||||
GetMemoryCacheEntryOptions(file, cacheEntry));
|
||||
}
|
||||
|
||||
if (cacheEntry != null)
|
||||
{
|
||||
if (cacheEntry.Success)
|
||||
|
|
@ -190,21 +198,17 @@ namespace Microsoft.AspNet.Mvc.Razor.Precompilation
|
|||
};
|
||||
}
|
||||
|
||||
private PrecompilationCacheEntry OnCacheMiss(ICacheSetContext cacheSetContext)
|
||||
private MemoryCacheEntryOptions GetMemoryCacheEntryOptions(
|
||||
RelativeFileInfo fileInfo,
|
||||
PrecompilationCacheEntry cacheEntry)
|
||||
{
|
||||
var fileInfo = (RelativeFileInfo)cacheSetContext.State;
|
||||
var entry = GetCacheEntry(fileInfo);
|
||||
|
||||
if (entry != null)
|
||||
var options = new MemoryCacheEntryOptions();
|
||||
options.AddExpirationTrigger(FileProvider.Watch(fileInfo.RelativePath));
|
||||
foreach (var path in ViewHierarchyUtility.GetViewImportsLocations(fileInfo.RelativePath))
|
||||
{
|
||||
cacheSetContext.AddExpirationTrigger(FileProvider.Watch(fileInfo.RelativePath));
|
||||
foreach (var path in ViewHierarchyUtility.GetViewImportsLocations(fileInfo.RelativePath))
|
||||
{
|
||||
cacheSetContext.AddExpirationTrigger(FileProvider.Watch(path));
|
||||
}
|
||||
options.AddExpirationTrigger(FileProvider.Watch(path));
|
||||
}
|
||||
|
||||
return entry;
|
||||
return options;
|
||||
}
|
||||
|
||||
private void GetFileInfosRecursive(string root, List<RelativeFileInfo> razorFiles)
|
||||
|
|
|
|||
|
|
@ -106,10 +106,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
public TimeSpan? ExpiresSliding { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="CachePreservationPriority"/> policy for the cache entry.
|
||||
/// Gets or sets the <see cref="CacheItemPriority"/> policy for the cache entry.
|
||||
/// </summary>
|
||||
[HtmlAttributeName(CachePriorityAttributeName)]
|
||||
public CachePreservationPriority? Priority { get; set; }
|
||||
public CacheItemPriority? Priority { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value which determines if the tag helper is enabled or not.
|
||||
|
|
@ -126,19 +126,14 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var key = GenerateKey(context);
|
||||
if (!MemoryCache.TryGetValue(key, out result))
|
||||
{
|
||||
// Create an EntryLink and flow it so that it is accessible via the ambient
|
||||
// EntryLinkHelpers.ContextLink for user code.
|
||||
var entryLink = new EntryLink();
|
||||
using (entryLink.FlowContext())
|
||||
// Create an entry link scope and flow it so that any triggers related to the cache entries
|
||||
// created within this scope get copied to this scope.
|
||||
using (var link = MemoryCache.CreateLinkingScope())
|
||||
{
|
||||
result = await context.GetChildContentAsync();
|
||||
}
|
||||
|
||||
MemoryCache.Set(key, cacheSetContext =>
|
||||
{
|
||||
UpdateCacheContext(cacheSetContext, entryLink);
|
||||
return result;
|
||||
});
|
||||
MemoryCache.Set(key, result, GetMemoryCacheEntryOptions(link));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -197,29 +192,31 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
}
|
||||
|
||||
// Internal for unit testing
|
||||
internal void UpdateCacheContext(ICacheSetContext cacheSetContext, EntryLink entryLink)
|
||||
internal MemoryCacheEntryOptions GetMemoryCacheEntryOptions(IEntryLink entryLink)
|
||||
{
|
||||
var options = new MemoryCacheEntryOptions();
|
||||
if (ExpiresOn != null)
|
||||
{
|
||||
cacheSetContext.SetAbsoluteExpiration(ExpiresOn.Value);
|
||||
options.SetAbsoluteExpiration(ExpiresOn.Value);
|
||||
}
|
||||
|
||||
if (ExpiresAfter != null)
|
||||
{
|
||||
cacheSetContext.SetAbsoluteExpiration(ExpiresAfter.Value);
|
||||
options.SetAbsoluteExpiration(ExpiresAfter.Value);
|
||||
}
|
||||
|
||||
if (ExpiresSliding != null)
|
||||
{
|
||||
cacheSetContext.SetSlidingExpiration(ExpiresSliding.Value);
|
||||
options.SetSlidingExpiration(ExpiresSliding.Value);
|
||||
}
|
||||
|
||||
if (Priority != null)
|
||||
{
|
||||
cacheSetContext.SetPriority(Priority.Value);
|
||||
options.SetPriority(Priority.Value);
|
||||
}
|
||||
|
||||
cacheSetContext.AddEntryLink(entryLink);
|
||||
options.AddEntryLink(entryLink);
|
||||
return options;
|
||||
}
|
||||
|
||||
private static void AddStringCollectionKey(StringBuilder builder,
|
||||
|
|
|
|||
|
|
@ -65,12 +65,17 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
}
|
||||
}
|
||||
|
||||
return _cache.GetOrSet(path, cacheGetOrSetContext =>
|
||||
string value;
|
||||
if(!_cache.TryGetValue(path, out value))
|
||||
{
|
||||
var trigger = _fileProvider.Watch(resolvedPath);
|
||||
cacheGetOrSetContext.AddExpirationTrigger(trigger);
|
||||
return QueryHelpers.AddQueryString(path, VersionKey, GetHashForFile(fileInfo));
|
||||
});
|
||||
value = QueryHelpers.AddQueryString(path, VersionKey, GetHashForFile(fileInfo));
|
||||
_cache.Set(
|
||||
path,
|
||||
value,
|
||||
new MemoryCacheEntryOptions().AddExpirationTrigger(_fileProvider.Watch(resolvedPath)));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private string GetHashForFile(IFileInfo fileInfo)
|
||||
|
|
|
|||
|
|
@ -101,16 +101,21 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
if (Cache != null)
|
||||
{
|
||||
var cacheKey = $"{nameof(GlobbingUrlBuilder)}-inc:{include}-exc:{exclude}";
|
||||
return Cache.GetOrSet(cacheKey, cacheSetContext =>
|
||||
IEnumerable<string> files;
|
||||
if (!Cache.TryGetValue(cacheKey, out files))
|
||||
{
|
||||
var options = new MemoryCacheEntryOptions();
|
||||
foreach (var pattern in includePatterns)
|
||||
{
|
||||
var trigger = FileProvider.Watch(pattern);
|
||||
cacheSetContext.AddExpirationTrigger(trigger);
|
||||
options.AddExpirationTrigger(trigger);
|
||||
}
|
||||
|
||||
return FindFiles(includePatterns, excludePatterns);
|
||||
});
|
||||
files = FindFiles(includePatterns, excludePatterns);
|
||||
|
||||
Cache.Set(cacheKey, files, options);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
return FindFiles(includePatterns, excludePatterns);
|
||||
|
|
@ -175,7 +180,6 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
// Only extension differs so just compare the extension
|
||||
var xExt = xExtIndex >= 0 ? x.Substring(xExtIndex) : string.Empty;
|
||||
var yExt = yExtIndex >= 0 ? y.Substring(yExtIndex) : string.Empty;
|
||||
|
||||
return string.Compare(xExt, yExt, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
_appServices = services;
|
||||
|
||||
// When ListenForMemoryPressure is true, the MemoryCache evicts items at every gen2 collection.
|
||||
// When CompactOnMemoryPressure is true, the MemoryCache evicts items at every gen2 collection.
|
||||
// In DTH, gen2 happens frequently enough to make it undesirable for caching precompilation results. We'll
|
||||
// disable listening for memory pressure for the MemoryCache instance used by precompilation.
|
||||
_memoryCache = new MemoryCache(new MemoryCacheOptions { ListenForMemoryPressure = false });
|
||||
_memoryCache = new MemoryCache(new MemoryCacheOptions { CompactOnMemoryPressure = false });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.AspNet.Mvc.Razor.Directives;
|
||||
using Microsoft.AspNet.Razor.Generator.Compiler;
|
||||
using Microsoft.Framework.Caching.Memory;
|
||||
using Microsoft.Framework.Caching.Memory.Infrastructure;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
|
@ -16,7 +17,7 @@ using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
|||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.Caching;
|
||||
using Microsoft.Framework.Caching.Memory;
|
||||
using Microsoft.Framework.Caching.Memory.Infrastructure;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -244,15 +245,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var childContent = "original-child-content";
|
||||
var cache = new Mock<IMemoryCache>();
|
||||
cache.CallBase = true;
|
||||
var value = new DefaultTagHelperContent().SetContent("ok");
|
||||
cache.Setup(c => c.Set(
|
||||
/*key*/ It.IsAny<string>(),
|
||||
/*link*/ It.IsAny<IEntryLink>(),
|
||||
/*state*/ It.IsAny<object>(),
|
||||
/*create*/ It.IsAny<Func<ICacheSetContext, object>>()))
|
||||
.Returns(new DefaultTagHelperContent().SetContent("ok"))
|
||||
/*value*/ value,
|
||||
/*optons*/ It.IsAny<MemoryCacheEntryOptions>()))
|
||||
.Returns(value)
|
||||
.Verifiable();
|
||||
object cacheResult;
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), It.IsAny<IEntryLink>(), out cacheResult))
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out cacheResult))
|
||||
.Returns(false);
|
||||
var tagHelperContext = GetTagHelperContext(id, childContent);
|
||||
var tagHelperOutput = new TagHelperOutput("cache", new TagHelperAttributeList());
|
||||
|
|
@ -270,9 +271,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
Assert.Equal(childContent, tagHelperOutput.Content.GetContent());
|
||||
cache.Verify(c => c.Set(
|
||||
/*key*/ It.IsAny<string>(),
|
||||
/*link*/ It.IsAny<IEntryLink>(),
|
||||
/*state*/ It.IsAny<object>(),
|
||||
/*create*/ It.IsAny<Func<ICacheSetContext, object>>()),
|
||||
/*value*/ It.IsAny<object>(),
|
||||
/*options*/ It.IsAny<MemoryCacheEntryOptions>()),
|
||||
Times.Never);
|
||||
}
|
||||
|
||||
|
|
@ -284,15 +284,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
var childContent = "original-child-content";
|
||||
var cache = new Mock<IMemoryCache>();
|
||||
cache.CallBase = true;
|
||||
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>(),
|
||||
/*link*/ It.IsAny<IEntryLink>(),
|
||||
/*state*/ It.IsAny<object>(),
|
||||
/*create*/ It.IsAny<Func<ICacheSetContext, object>>()))
|
||||
.Returns(new DefaultTagHelperContent().SetContent("ok"))
|
||||
/*value*/ It.IsAny<object>(),
|
||||
/*options*/ It.IsAny<MemoryCacheEntryOptions>()))
|
||||
.Returns(value)
|
||||
.Verifiable();
|
||||
object cacheResult;
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), It.IsAny<IEntryLink>(), out cacheResult))
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out cacheResult))
|
||||
.Returns(false);
|
||||
var tagHelperContext = GetTagHelperContext(id, childContent);
|
||||
var tagHelperOutput = new TagHelperOutput("cache", new TagHelperAttributeList());
|
||||
|
|
@ -313,9 +314,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
Assert.Equal(childContent, tagHelperOutput.Content.GetContent());
|
||||
cache.Verify(c => c.Set(
|
||||
/*key*/ It.IsAny<string>(),
|
||||
/*link*/ It.IsAny<IEntryLink>(),
|
||||
/*state*/ It.IsAny<object>(),
|
||||
/*create*/ It.IsAny<Func<ICacheSetContext, object>>()),
|
||||
/*value*/ It.IsAny<object>(),
|
||||
/*options*/ It.IsAny<MemoryCacheEntryOptions>()),
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
|
|
@ -421,14 +421,11 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateCacheContext_SetsAbsoluteExpiration_IfExpiresOnIsSet()
|
||||
public void UpdateCacheEntryOptions_SetsAbsoluteExpiration_IfExpiresOnIsSet()
|
||||
{
|
||||
// Arrange
|
||||
var expiresOn = DateTimeOffset.UtcNow.AddMinutes(4);
|
||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||
var cacheContext = new Mock<ICacheSetContext>(MockBehavior.Strict);
|
||||
cacheContext.Setup(c => c.SetAbsoluteExpiration(expiresOn))
|
||||
.Verifiable();
|
||||
var cacheTagHelper = new CacheTagHelper
|
||||
{
|
||||
MemoryCache = cache,
|
||||
|
|
@ -436,21 +433,18 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
};
|
||||
|
||||
// Act
|
||||
cacheTagHelper.UpdateCacheContext(cacheContext.Object, new EntryLink());
|
||||
var cacheEntryOptions = cacheTagHelper.GetMemoryCacheEntryOptions(new EntryLink());
|
||||
|
||||
// Assert
|
||||
cacheContext.Verify();
|
||||
Assert.Equal(expiresOn, cacheEntryOptions.AbsoluteExpiration);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateCacheContext_UsesAbsoluteExpirationSpecifiedOnEntryLink()
|
||||
public void UpdateCacheEntryOptions_UsesAbsoluteExpirationSpecifiedOnEntryLink()
|
||||
{
|
||||
// Arrange
|
||||
var expiresOn = DateTimeOffset.UtcNow.AddMinutes(7);
|
||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||
var cacheContext = new Mock<ICacheSetContext>(MockBehavior.Strict);
|
||||
cacheContext.Setup(c => c.SetAbsoluteExpiration(expiresOn))
|
||||
.Verifiable();
|
||||
var cacheTagHelper = new CacheTagHelper
|
||||
{
|
||||
MemoryCache = cache
|
||||
|
|
@ -460,29 +454,19 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
entryLink.SetAbsoluteExpiration(expiresOn);
|
||||
|
||||
// Act
|
||||
cacheTagHelper.UpdateCacheContext(cacheContext.Object, entryLink);
|
||||
var cacheEntryOptions = cacheTagHelper.GetMemoryCacheEntryOptions(entryLink);
|
||||
|
||||
// Assert
|
||||
cacheContext.Verify();
|
||||
Assert.Equal(expiresOn, cacheEntryOptions.AbsoluteExpiration);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateCacheContext_PrefersAbsoluteExpirationSpecifiedOnEntryLinkOverExpiresOn()
|
||||
public void UpdateCacheEntryOptions_PrefersAbsoluteExpirationSpecifiedOnEntryLinkOverExpiresOn()
|
||||
{
|
||||
// Arrange
|
||||
var expiresOn1 = DateTimeOffset.UtcNow.AddDays(12);
|
||||
var expiresOn2 = DateTimeOffset.UtcNow.AddMinutes(4);
|
||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||
var cacheContext = new Mock<ICacheSetContext>();
|
||||
var sequence = new MockSequence();
|
||||
cacheContext.InSequence(sequence)
|
||||
.Setup(c => c.SetAbsoluteExpiration(expiresOn1))
|
||||
.Verifiable();
|
||||
|
||||
cacheContext.InSequence(sequence)
|
||||
.Setup(c => c.SetAbsoluteExpiration(expiresOn2))
|
||||
.Verifiable();
|
||||
|
||||
var cacheTagHelper = new CacheTagHelper
|
||||
{
|
||||
MemoryCache = cache,
|
||||
|
|
@ -493,21 +477,18 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
entryLink.SetAbsoluteExpiration(expiresOn2);
|
||||
|
||||
// Act
|
||||
cacheTagHelper.UpdateCacheContext(cacheContext.Object, entryLink);
|
||||
var cacheEntryOptions = cacheTagHelper.GetMemoryCacheEntryOptions(entryLink);
|
||||
|
||||
// Assert
|
||||
cacheContext.Verify();
|
||||
Assert.Equal(expiresOn2, cacheEntryOptions.AbsoluteExpiration);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateCacheContext_SetsAbsoluteExpiration_IfExpiresAfterIsSet()
|
||||
public void UpdateCacheEntryOptions_SetsAbsoluteExpiration_IfExpiresAfterIsSet()
|
||||
{
|
||||
// Arrange
|
||||
var expiresAfter = TimeSpan.FromSeconds(42);
|
||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||
var cacheContext = new Mock<ICacheSetContext>();
|
||||
cacheContext.Setup(c => c.SetAbsoluteExpiration(expiresAfter))
|
||||
.Verifiable();
|
||||
var cacheTagHelper = new CacheTagHelper
|
||||
{
|
||||
MemoryCache = cache,
|
||||
|
|
@ -515,21 +496,18 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
};
|
||||
|
||||
// Act
|
||||
cacheTagHelper.UpdateCacheContext(cacheContext.Object, new EntryLink());
|
||||
var cacheEntryOptions = cacheTagHelper.GetMemoryCacheEntryOptions(new EntryLink());
|
||||
|
||||
// Assert
|
||||
cacheContext.Verify();
|
||||
Assert.Equal(expiresAfter, cacheEntryOptions.AbsoluteExpirationRelativeToNow);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateCacheContext_SetsSlidingExpiration_IfExpiresSlidingIsSet()
|
||||
public void UpdateCacheEntryOptions_SetsSlidingExpiration_IfExpiresSlidingIsSet()
|
||||
{
|
||||
// Arrange
|
||||
var expiresSliding = TimeSpan.FromSeconds(37);
|
||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||
var cacheContext = new Mock<ICacheSetContext>();
|
||||
cacheContext.Setup(c => c.SetSlidingExpiration(expiresSliding))
|
||||
.Verifiable();
|
||||
var cacheTagHelper = new CacheTagHelper
|
||||
{
|
||||
MemoryCache = cache,
|
||||
|
|
@ -537,21 +515,18 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
};
|
||||
|
||||
// Act
|
||||
cacheTagHelper.UpdateCacheContext(cacheContext.Object, new EntryLink());
|
||||
var cacheEntryOptions = cacheTagHelper.GetMemoryCacheEntryOptions(new EntryLink());
|
||||
|
||||
// Assert
|
||||
cacheContext.Verify();
|
||||
Assert.Equal(expiresSliding, cacheEntryOptions.SlidingExpiration);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateCacheContext_SetsCachePreservationPriority()
|
||||
public void UpdateCacheEntryOptions_SetsCachePreservationPriority()
|
||||
{
|
||||
// Arrange
|
||||
var priority = CachePreservationPriority.High;
|
||||
var priority = CacheItemPriority.High;
|
||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||
var cacheContext = new Mock<ICacheSetContext>();
|
||||
cacheContext.Setup(c => c.SetPriority(priority))
|
||||
.Verifiable();
|
||||
var cacheTagHelper = new CacheTagHelper
|
||||
{
|
||||
MemoryCache = cache,
|
||||
|
|
@ -559,26 +534,19 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
};
|
||||
|
||||
// Act
|
||||
cacheTagHelper.UpdateCacheContext(cacheContext.Object, new EntryLink());
|
||||
var cacheEntryOptions = cacheTagHelper.GetMemoryCacheEntryOptions(new EntryLink());
|
||||
|
||||
// Assert
|
||||
cacheContext.Verify();
|
||||
Assert.Equal(priority, cacheEntryOptions.Priority);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateCacheContext_CopiesTriggersFromEntryLink()
|
||||
public void UpdateCacheEntryOptions_CopiesTriggersFromEntryLink()
|
||||
{
|
||||
// Arrange
|
||||
var expiresSliding = TimeSpan.FromSeconds(30);
|
||||
var expected = new[] { Mock.Of<IExpirationTrigger>(), Mock.Of<IExpirationTrigger>() };
|
||||
var triggers = new List<IExpirationTrigger>();
|
||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||
var cacheContext = new Mock<ICacheSetContext>();
|
||||
cacheContext.Setup(c => c.SetSlidingExpiration(expiresSliding))
|
||||
.Verifiable();
|
||||
cacheContext.Setup(c => c.AddExpirationTrigger(It.IsAny<IExpirationTrigger>()))
|
||||
.Callback<IExpirationTrigger>(triggers.Add)
|
||||
.Verifiable();
|
||||
var cacheTagHelper = new CacheTagHelper
|
||||
{
|
||||
MemoryCache = cache,
|
||||
|
|
@ -589,11 +557,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
entryLink.AddExpirationTriggers(expected);
|
||||
|
||||
// Act
|
||||
cacheTagHelper.UpdateCacheContext(cacheContext.Object, entryLink);
|
||||
var cacheEntryOptions = cacheTagHelper.GetMemoryCacheEntryOptions(entryLink);
|
||||
|
||||
// Assert
|
||||
cacheContext.Verify();
|
||||
Assert.Equal(expected, triggers);
|
||||
Assert.Equal(expected, cacheEntryOptions.Triggers.ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -770,19 +737,22 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
expectedContent.SetContent("some-content");
|
||||
var tokenSource = new CancellationTokenSource();
|
||||
var cache = new MemoryCache(new MemoryCacheOptions());
|
||||
var cacheEntryOptions = new MemoryCacheEntryOptions()
|
||||
.AddExpirationTrigger(new CancellationTokenTrigger(tokenSource.Token));
|
||||
var tagHelperContext = new TagHelperContext(
|
||||
allAttributes: new TagHelperAttributeList(),
|
||||
items: new Dictionary<object, object>(),
|
||||
uniqueId: id,
|
||||
getChildContentAsync: () =>
|
||||
{
|
||||
var entryLink = EntryLinkHelpers.ContextLink;
|
||||
Assert.NotNull(entryLink);
|
||||
entryLink.AddExpirationTriggers(new[]
|
||||
TagHelperContent tagHelperContent;
|
||||
if(!cache.TryGetValue("key1", out tagHelperContent))
|
||||
{
|
||||
new CancellationTokenTrigger(tokenSource.Token)
|
||||
});
|
||||
return Task.FromResult<TagHelperContent>(expectedContent);
|
||||
tagHelperContent = expectedContent;
|
||||
cache.Set("key1", tagHelperContent, cacheEntryOptions);
|
||||
}
|
||||
|
||||
return Task.FromResult(tagHelperContent);
|
||||
});
|
||||
var tagHelperOutput = new TagHelperOutput("cache", new TagHelperAttributeList { { "attr", "value" } });
|
||||
tagHelperOutput.PreContent.SetContent("<cache>");
|
||||
|
|
|
|||
|
|
@ -260,29 +260,14 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
object result = null;
|
||||
var cache = new Mock<IMemoryCache>();
|
||||
cache.CallBase = true;
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), It.IsAny<IEntryLink>(), out result))
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out result))
|
||||
.Returns(result != null);
|
||||
|
||||
var cacheSetContext = new Mock<ICacheSetContext>();
|
||||
cacheSetContext.Setup(c => c.AddExpirationTrigger(It.IsAny<IExpirationTrigger>()));
|
||||
cache
|
||||
.Setup(
|
||||
cache.Setup(
|
||||
c => c.Set(
|
||||
/*key*/ It.IsAny<string>(),
|
||||
/*link*/ It.IsAny<IEntryLink>(),
|
||||
/*state*/ It.IsAny<object>(),
|
||||
/*create*/ It.IsAny<Func<ICacheSetContext, object>>()))
|
||||
.Returns((
|
||||
string input,
|
||||
IEntryLink entryLink,
|
||||
object state,
|
||||
Func<ICacheSetContext, object> create) =>
|
||||
{
|
||||
{
|
||||
cacheSetContext.Setup(c => c.State).Returns(state);
|
||||
return create(cacheSetContext.Object);
|
||||
}
|
||||
});
|
||||
/*value*/ It.IsAny<object>(),
|
||||
/*options*/ It.IsAny<MemoryCacheEntryOptions>()))
|
||||
.Returns(new object());
|
||||
return cache.Object;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,21 +141,13 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
object cacheValue = null;
|
||||
var cache = new Mock<IMemoryCache>();
|
||||
cache.CallBase = true;
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), It.IsAny<IEntryLink>(), out cacheValue))
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out cacheValue))
|
||||
.Returns(cacheValue != null);
|
||||
var cacheSetContext = new Mock<ICacheSetContext>();
|
||||
cacheSetContext.Setup(c => c.AddExpirationTrigger(trigger.Object)).Verifiable();
|
||||
cache.Setup(c => c.Set(
|
||||
/*key*/ filePath,
|
||||
/*link*/ It.IsAny<IEntryLink>(),
|
||||
/*state*/ It.IsAny<object>(),
|
||||
/*create*/ It.IsAny<Func<ICacheSetContext, object>>()))
|
||||
.Returns<string, IEntryLink, object, Func<ICacheSetContext, object>>(
|
||||
(key, link, state, create) =>
|
||||
{
|
||||
cacheSetContext.Setup(c => c.State).Returns(state);
|
||||
return create(cacheSetContext.Object);
|
||||
})
|
||||
/*value*/ It.IsAny<object>(),
|
||||
/*options*/ It.IsAny<MemoryCacheEntryOptions>()))
|
||||
.Returns(new object())
|
||||
.Verifiable();
|
||||
var fileVersionProvider = new FileVersionProvider(
|
||||
hostingEnvironment.WebRootFileProvider,
|
||||
|
|
@ -167,7 +159,6 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
|
||||
// Assert
|
||||
Assert.Equal(filePath + "?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", result);
|
||||
cacheSetContext.VerifyAll();
|
||||
cache.VerifyAll();
|
||||
}
|
||||
|
||||
|
|
@ -211,29 +202,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
{
|
||||
var cache = new Mock<IMemoryCache>();
|
||||
cache.CallBase = true;
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), It.IsAny<IEntryLink>(), out result))
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out result))
|
||||
.Returns(result != null);
|
||||
|
||||
var cacheSetContext = new Mock<ICacheSetContext>();
|
||||
cacheSetContext.Setup(c => c.AddExpirationTrigger(It.IsAny<IExpirationTrigger>()));
|
||||
cache
|
||||
.Setup(
|
||||
c => c.Set(
|
||||
/*key*/ It.IsAny<string>(),
|
||||
/*link*/ It.IsAny<IEntryLink>(),
|
||||
/*state*/ It.IsAny<object>(),
|
||||
/*create*/ It.IsAny<Func<ICacheSetContext, object>>()))
|
||||
.Returns((
|
||||
string input,
|
||||
IEntryLink entryLink,
|
||||
object state,
|
||||
Func<ICacheSetContext, object> create) =>
|
||||
{
|
||||
{
|
||||
cacheSetContext.Setup(c => c.State).Returns(state);
|
||||
return create(cacheSetContext.Object);
|
||||
}
|
||||
});
|
||||
/*value*/ It.IsAny<object>(),
|
||||
/*options*/ It.IsAny<MemoryCacheEntryOptions>()))
|
||||
.Returns(new object());
|
||||
return cache.Object;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -252,18 +252,19 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
{
|
||||
// Arrange
|
||||
var fileProvider = MakeFileProvider();
|
||||
var cache = MakeCache(new List<string> { "/blank.css", "/site.css" });
|
||||
var expected = new List<string> { "/blank.css", "/site.css" };
|
||||
var cache = MakeCache(result: expected);
|
||||
var requestPathBase = PathString.Empty;
|
||||
var globbingUrlBuilder = new GlobbingUrlBuilder(fileProvider, cache, requestPathBase);
|
||||
|
||||
// Act
|
||||
var urlList = globbingUrlBuilder.BuildUrlList(
|
||||
var actual = globbingUrlBuilder.BuildUrlList(
|
||||
staticUrl: null,
|
||||
includePattern: "**/*.css",
|
||||
excludePattern: null);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(urlList,
|
||||
Assert.Collection(actual,
|
||||
url => Assert.Equal("/blank.css", url),
|
||||
url => Assert.Equal("/site.css", url));
|
||||
}
|
||||
|
|
@ -276,19 +277,11 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
var fileProvider = MakeFileProvider(MakeDirectoryContents("site.css", "blank.css"));
|
||||
Mock.Get(fileProvider).Setup(f => f.Watch(It.IsAny<string>())).Returns(trigger.Object);
|
||||
var cache = MakeCache();
|
||||
var cacheSetContext = new Mock<ICacheSetContext>();
|
||||
cacheSetContext.Setup(c => c.AddExpirationTrigger(trigger.Object)).Verifiable();
|
||||
Mock.Get(cache).Setup(c => c.Set(
|
||||
/*key*/ It.IsAny<string>(),
|
||||
/*link*/ It.IsAny<IEntryLink>(),
|
||||
/*state*/ It.IsAny<object>(),
|
||||
/*create*/ It.IsAny<Func<ICacheSetContext, object>>()))
|
||||
.Returns<string, IEntryLink, object, Func<ICacheSetContext, object>>(
|
||||
(key, link, state, create) =>
|
||||
{
|
||||
cacheSetContext.Setup(c => c.State).Returns(state);
|
||||
return create(cacheSetContext.Object);
|
||||
})
|
||||
/*value*/ It.IsAny<object>(),
|
||||
/*options*/ It.IsAny<MemoryCacheEntryOptions>()))
|
||||
.Returns(new object())
|
||||
.Verifiable();
|
||||
var requestPathBase = PathString.Empty;
|
||||
var globbingUrlBuilder = new GlobbingUrlBuilder(fileProvider, cache, requestPathBase);
|
||||
|
|
@ -303,7 +296,6 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
Assert.Collection(urlList,
|
||||
url => Assert.Equal("/blank.css", url),
|
||||
url => Assert.Equal("/site.css", url));
|
||||
cacheSetContext.VerifyAll();
|
||||
Mock.Get(cache).VerifyAll();
|
||||
}
|
||||
|
||||
|
|
@ -394,11 +386,11 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
{
|
||||
throw new ArgumentException(nameof(rootNode));
|
||||
}
|
||||
|
||||
|
||||
var fileProvider = new Mock<IFileProvider>(MockBehavior.Strict);
|
||||
fileProvider.Setup(fp => fp.GetDirectoryContents(string.Empty))
|
||||
.Returns(MakeDirectoryContents(rootNode, fileProvider));
|
||||
|
||||
|
||||
return fileProvider.Object;
|
||||
}
|
||||
|
||||
|
|
@ -418,7 +410,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
.Returns(MakeDirectoryContents(node, fileProviderMock));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var directoryContents = new Mock<IDirectoryContents>();
|
||||
directoryContents.Setup(dc => dc.GetEnumerator()).Returns(children.GetEnumerator());
|
||||
|
||||
|
|
@ -450,7 +442,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
|||
private static IMemoryCache MakeCache(object result = null)
|
||||
{
|
||||
var cache = new Mock<IMemoryCache>();
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), It.IsAny<IEntryLink>(), out result))
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out result))
|
||||
.Returns(result != null);
|
||||
return cache.Object;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -760,29 +760,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
{
|
||||
var cache = new Mock<IMemoryCache>();
|
||||
cache.CallBase = true;
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), It.IsAny<IEntryLink>(), out result))
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out result))
|
||||
.Returns(result != null);
|
||||
|
||||
var cacheSetContext = new Mock<ICacheSetContext>();
|
||||
cacheSetContext.Setup(c => c.AddExpirationTrigger(It.IsAny<IExpirationTrigger>()));
|
||||
cache
|
||||
.Setup(
|
||||
c => c.Set(
|
||||
/*key*/ It.IsAny<string>(),
|
||||
/*link*/ It.IsAny<IEntryLink>(),
|
||||
/*state*/ It.IsAny<object>(),
|
||||
/*create*/ It.IsAny<Func<ICacheSetContext, object>>()))
|
||||
.Returns((
|
||||
string input,
|
||||
IEntryLink entryLink,
|
||||
object state,
|
||||
Func<ICacheSetContext, object> create) =>
|
||||
{
|
||||
{
|
||||
cacheSetContext.Setup(c => c.State).Returns(state);
|
||||
return create(cacheSetContext.Object);
|
||||
}
|
||||
});
|
||||
/*value*/ It.IsAny<object>(),
|
||||
/*options*/ It.IsAny<MemoryCacheEntryOptions>()))
|
||||
.Returns(result);
|
||||
return cache.Object;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -842,29 +842,18 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
|||
{
|
||||
var cache = new Mock<IMemoryCache>();
|
||||
cache.CallBase = true;
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), It.IsAny<IEntryLink>(), out result))
|
||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out result))
|
||||
.Returns(result != null);
|
||||
|
||||
var cacheSetContext = new Mock<ICacheSetContext>();
|
||||
cacheSetContext.Setup(c => c.AddExpirationTrigger(It.IsAny<IExpirationTrigger>()));
|
||||
var cacheEntryOptions = new MemoryCacheEntryOptions();
|
||||
cacheEntryOptions.AddExpirationTrigger(new Mock<IExpirationTrigger>().Object);
|
||||
cache
|
||||
.Setup(
|
||||
c => c.Set(
|
||||
/*key*/ It.IsAny<string>(),
|
||||
/*link*/ It.IsAny<IEntryLink>(),
|
||||
/*state*/ It.IsAny<object>(),
|
||||
/*create*/ It.IsAny<Func<ICacheSetContext, object>>()))
|
||||
.Returns((
|
||||
string input,
|
||||
IEntryLink entryLink,
|
||||
object state,
|
||||
Func<ICacheSetContext, object> create) =>
|
||||
{
|
||||
{
|
||||
cacheSetContext.Setup(c => c.State).Returns(state);
|
||||
return create(cacheSetContext.Object);
|
||||
}
|
||||
});
|
||||
/*value*/ It.IsAny<object>(),
|
||||
/*options*/ cacheEntryOptions))
|
||||
.Returns(result);
|
||||
return cache.Object;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,11 +12,18 @@ namespace MvcTagHelpersWebSite.Components
|
|||
[Activate]
|
||||
public ProductsService ProductsService { get; set; }
|
||||
|
||||
[Activate]
|
||||
public IMemoryCache Cache { get; set; }
|
||||
|
||||
public IViewComponentResult Invoke(string category)
|
||||
{
|
||||
IExpirationTrigger trigger;
|
||||
var products = ProductsService.GetProducts(category, out trigger);
|
||||
EntryLinkHelpers.ContextLink.AddExpirationTriggers(new[] { trigger });
|
||||
string products;
|
||||
if (!Cache.TryGetValue(category, out products))
|
||||
{
|
||||
IExpirationTrigger trigger;
|
||||
products = ProductsService.GetProducts(category, out trigger);
|
||||
Cache.Set(category, products, new MemoryCacheEntryOptions().AddExpirationTrigger(trigger));
|
||||
}
|
||||
|
||||
ViewData["Products"] = products;
|
||||
return View();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
@using Microsoft.Framework.Caching.Memory
|
||||
<cache expires-after="TimeSpan.FromSeconds(1)" priority="CachePreservationPriority.Low">
|
||||
<cache expires-after="TimeSpan.FromSeconds(1)" priority="CacheItemPriority.Low">
|
||||
Cached content for @ViewBag.ProductId
|
||||
</cache>
|
||||
|
|
|
|||
Loading…
Reference in New Issue