diff --git a/samples/MvcSandbox/Startup.cs b/samples/MvcSandbox/Startup.cs index 1b32b78bd8..774d6bd710 100644 --- a/samples/MvcSandbox/Startup.cs +++ b/samples/MvcSandbox/Startup.cs @@ -2,15 +2,10 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.IO; -using Microsoft.AspNetCore.Antiforgery; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc.Razor.Internal; -using Microsoft.AspNetCore.Razor.Language; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; namespace MvcSandbox { @@ -20,11 +15,6 @@ namespace MvcSandbox public void ConfigureServices(IServiceCollection services) { services.AddMvc(); - services.AddSingleton(new PhysicalFileProvider(Path.GetFullPath("."))); - - services.Insert(0, ServiceDescriptor.Singleton( - typeof(IConfigureOptions), - new ConfigureOptions(options => options.Cookie.Name = ""))); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/samples/MvcSandbox/Views/Home/Index.cshtml b/samples/MvcSandbox/Views/Home/Index.cshtml index 93a5e737b0..15a5130409 100644 --- a/samples/MvcSandbox/Views/Home/Index.cshtml +++ b/samples/MvcSandbox/Views/Home/Index.cshtml @@ -9,4 +9,4 @@
  • This sandbox should give you a quick view of a basic MVC application.
  • - + \ No newline at end of file diff --git a/samples/MvcSandbox/Views/Shared/_Layout.cshtml b/samples/MvcSandbox/Views/Shared/_Layout.cshtml index 77b4265ee2..9f4e4c7ff0 100644 --- a/samples/MvcSandbox/Views/Shared/_Layout.cshtml +++ b/samples/MvcSandbox/Views/Shared/_Layout.cshtml @@ -3,6 +3,7 @@ + @ViewData["Title"] - MvcSandbox diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/Cache/DistributedCacheTagHelperService.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/Cache/DistributedCacheTagHelperService.cs index 571c2f3fe5..34629a2664 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/Cache/DistributedCacheTagHelperService.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/Cache/DistributedCacheTagHelperService.cs @@ -85,6 +85,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Cache // Is there any request already processing the value? if (!_workers.TryGetValue(key, out result)) { + // There is a small race condition here between TryGetValue and TryAdd that might cause the + // content to be computed more than once. We don't care about this race as the probability of + // happening is very small and the impact is not critical. var tcs = new TaskCompletionSource(); _workers.TryAdd(key, tcs.Task); diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/CacheTagHelper.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/CacheTagHelper.cs index 5d5bd1290c..7984e1fc19 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/CacheTagHelper.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/CacheTagHelper.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Mvc.TagHelpers.Cache; +using Microsoft.AspNetCore.Mvc.TagHelpers.Internal; using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal; using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.Extensions.Caching.Memory; @@ -29,14 +30,22 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers private const string CachePriorityAttributeName = "priority"; + // We need to come up with a value for the size of entries when storing a gating Task on the cache. Any value + // greater than 0 will suffice. We choose 56 bytes as an approximation of the size of the task that we store + // in the cache. This size got calculated as an upper bound for the size of an actual task on an x64 architecture + // and corresponds to 24 bytes for the object header block plus the 40 bytes added by the members of the task + // object. + private const int PlaceholderSize = 64; + /// /// Creates a new . /// - /// The . + /// The factory containing the private instance + /// used by the . /// The to use. - public CacheTagHelper(IMemoryCache memoryCache, HtmlEncoder htmlEncoder) : base(htmlEncoder) + public CacheTagHelper(CacheTagHelperMemoryCacheFactory factory, HtmlEncoder htmlEncoder) : base(htmlEncoder) { - MemoryCache = memoryCache; + MemoryCache = factory.Cache; } /// @@ -93,7 +102,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var options = GetMemoryCacheEntryOptions(); options.AddExpirationToken(new CancellationChangeToken(tokenSource.Token)); - + options.SetSize(PlaceholderSize); var tcs = new TaskCompletionSource(); // The returned value is ignored, we only do this so that @@ -116,11 +125,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // such that the tokens are inherited. var result = ProcessContentAsync(output); - - entry.SetOptions(options); - entry.Value = result; - content = await result; + options.SetSize(GetSize(content)); + entry.SetOptions(options); + + entry.Value = result; } tcs.SetResult(content); @@ -143,6 +152,22 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers } } + private long GetSize(IHtmlContent content) + { + if (content is CharBufferHtmlContent charBuffer) + { + // We need to multiply the size of the buffer + // by a factor of two due to the fact that + // characters in .NET are UTF-16 which means + // every character uses two bytes (surrogates + // are represented as two characters) + return charBuffer.Buffer.Length * sizeof(char); + } + + Debug.Fail($"{nameof(content)} should be an {nameof(CharBufferHtmlContent)}."); + return -1; + } + // Internal for unit testing internal MemoryCacheEntryOptions GetMemoryCacheEntryOptions() { @@ -226,17 +251,19 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers _buffer = buffer; } + public PagedCharBuffer Buffer => _buffer; + public void WriteTo(TextWriter writer, HtmlEncoder encoder) { - var length = _buffer.Length; + var length = Buffer.Length; if (length == 0) { return; } - for (var i = 0; i < _buffer.Pages.Count; i++) + for (var i = 0; i < Buffer.Pages.Count; i++) { - var page = _buffer.Pages[i]; + var page = Buffer.Pages[i]; var pageLength = Math.Min(length, page.Length); writer.Write(page, index: 0, count: pageLength); length -= pageLength; diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/CacheTagHelperOptions.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/CacheTagHelperOptions.cs new file mode 100644 index 0000000000..308a60273d --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/CacheTagHelperOptions.cs @@ -0,0 +1,17 @@ +// 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. + +namespace Microsoft.AspNetCore.Mvc.TagHelpers +{ + /// + /// Provides programmatic configuration for the cache tag helper in the MVC framework. + /// + public class CacheTagHelperOptions + { + /// + /// The maximum total size in bytes that will be cached by the + /// at any given time. + /// + public long SizeLimit { get; set; } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/DependencyInjection/TagHelperExtensions.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/DependencyInjection/TagHelperExtensions.cs index 4895085d0f..20dd02be91 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/DependencyInjection/TagHelperExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/DependencyInjection/TagHelperExtensions.cs @@ -2,18 +2,20 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using Microsoft.AspNetCore.Mvc.TagHelpers; using Microsoft.AspNetCore.Mvc.TagHelpers.Cache; -using Microsoft.Extensions.Caching.Distributed; -using Microsoft.Extensions.Caching.Memory; +using Microsoft.AspNetCore.Mvc.TagHelpers.Internal; using Microsoft.Extensions.DependencyInjection.Extensions; namespace Microsoft.Extensions.DependencyInjection -{ +{ /// /// Extension methods for configuring Razor cache tag helpers. /// public static class TagHelperServicesExtensions { + private const int DefaultCacheMaximumSizeInBytes = 100 * 1024 * 1024; // 100MB + /// /// Adds MVC cache tag helper services to the application. /// @@ -26,13 +28,60 @@ namespace Microsoft.Extensions.DependencyInjection throw new ArgumentNullException(nameof(builder)); } - builder.Services.TryAddTransient(); - builder.Services.TryAddTransient(); + builder.Services.TryAddSingleton(); + builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); // Required default services for cache tag helpers - builder.Services.TryAddSingleton(); - builder.Services.TryAddSingleton(); + builder.Services.AddDistributedMemoryCache(); + builder.Services.TryAddSingleton(); + builder.AddCacheTagHelperLimits(options => options.SizeLimit = DefaultCacheMaximumSizeInBytes); + + return builder; + } + + /// + /// Configures the memory size limits on the cache of the . + /// + /// The . + /// The to configure the cache options. + /// The . + public static IMvcBuilder AddCacheTagHelperLimits(this IMvcBuilder builder, Action configure) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + if (configure == null) + { + throw new ArgumentNullException(nameof(configure)); + } + + builder.Services.Configure(configure); + + return builder; + } + + /// + /// Configures the memory size limits on the cache of the . + /// + /// The . + /// The to configure the cache options. + /// The . + public static IMvcCoreBuilder AddCacheTagHelperLimits(this IMvcCoreBuilder builder, Action configure) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + if (configure == null) + { + throw new ArgumentNullException(nameof(configure)); + } + + builder.Services.Configure(configure); return builder; } diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/CacheTagHelperMemoryCacheFactory.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/CacheTagHelperMemoryCacheFactory.cs new file mode 100644 index 0000000000..7239f80260 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/CacheTagHelperMemoryCacheFactory.cs @@ -0,0 +1,27 @@ +// 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 Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal +{ + public class CacheTagHelperMemoryCacheFactory + { + public CacheTagHelperMemoryCacheFactory(IOptions options) + { + Cache = new MemoryCache(new MemoryCacheOptions + { + SizeLimit = options.Value.SizeLimit + }); + } + + // For testing only. + internal CacheTagHelperMemoryCacheFactory(IMemoryCache cache) + { + Cache = cache; + } + + public IMemoryCache Cache { get; } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/CacheTagHelperTest.cs b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/CacheTagHelperTest.cs index fe9915790f..31639c0456 100644 --- a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/CacheTagHelperTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/CacheTagHelperTest.cs @@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.TagHelpers.Cache; +using Microsoft.AspNetCore.Mvc.TagHelpers.Internal; using Microsoft.AspNetCore.Mvc.ViewEngines; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; @@ -48,7 +49,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelperOutput = GetTagHelperOutput( attributes: new TagHelperAttributeList(), childContent: childContent); - var cacheTagHelper = new CacheTagHelper(cache.Object, new HtmlTestEncoder()) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache.Object), new HtmlTestEncoder()) { ViewContext = GetViewContext(), Enabled = false @@ -75,7 +76,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelperOutput = GetTagHelperOutput( attributes: new TagHelperAttributeList(), childContent: childContent); - var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { ViewContext = GetViewContext(), Enabled = true @@ -102,7 +103,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelperOutput1 = GetTagHelperOutput( attributes: new TagHelperAttributeList(), childContent: childContent); - var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { VaryByQuery = "key1,key2", ViewContext = GetViewContext(), @@ -124,7 +125,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelperOutput2 = GetTagHelperOutput( attributes: new TagHelperAttributeList(), childContent: "different-content"); - var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { VaryByQuery = "key1,key2", ViewContext = GetViewContext(), @@ -153,7 +154,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1); tagHelperOutput1.PreContent.Append(""); tagHelperOutput1.PostContent.SetContent(""); - var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { VaryByCookie = "cookie1,cookie2", ViewContext = GetViewContext(), @@ -175,7 +176,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2); tagHelperOutput2.PreContent.SetContent(""); tagHelperOutput2.PostContent.SetContent(""); - var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { VaryByCookie = "cookie1,cookie2", ViewContext = GetViewContext(), @@ -198,7 +199,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // Arrange var expiresOn = DateTimeOffset.UtcNow.AddMinutes(4); var cache = new MemoryCache(new MemoryCacheOptions()); - var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { ExpiresOn = expiresOn }; @@ -210,13 +211,58 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers Assert.Equal(expiresOn, cacheEntryOptions.AbsoluteExpiration); } + [Fact] + public async Task ProcessAsync_SetsEntrySize_ForPlaceholderAndFinalCacheEntries() + { + // Arrange + var mockCache = new Mock(); + var tempEntry = new Mock(); + tempEntry.SetupAllProperties(); + tempEntry.Setup(e => e.ExpirationTokens).Returns(new List()); + tempEntry.Setup(e => e.PostEvictionCallbacks).Returns(new List()); + var finalEntry = new Mock(); + finalEntry.SetupAllProperties(); + finalEntry.Setup(e => e.ExpirationTokens).Returns(new List()); + finalEntry.Setup(e => e.PostEvictionCallbacks).Returns(new List()); + object value; + mockCache + .Setup(s => s.TryGetValue(It.IsAny(), out value)) + .Returns(false); + + mockCache.SetupSequence(mc => mc.CreateEntry(It.IsAny())) + .Returns(tempEntry.Object) + .Returns(finalEntry.Object); + + var id = "unique-id"; + var childContent1 = "original-child-content"; + var tagHelperContext1 = GetTagHelperContext(id); + var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1); + tagHelperOutput1.PreContent.Append(""); + tagHelperOutput1.PostContent.SetContent(""); + var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(mockCache.Object), new HtmlTestEncoder()) + { + ViewContext = GetViewContext(), + }; + + // Act + await cacheTagHelper1.ProcessAsync(tagHelperContext1, tagHelperOutput1); + + // Assert + Assert.Empty(tagHelperOutput1.PreContent.GetContent()); + Assert.Empty(tagHelperOutput1.PostContent.GetContent()); + Assert.True(tagHelperOutput1.IsContentModified); + Assert.Equal(childContent1, tagHelperOutput1.Content.GetContent()); + tempEntry.VerifySet(e => e.Size = 64); + finalEntry.VerifySet(e => e.Size = childContent1.Length * 2); + } + [Fact] public void UpdateCacheEntryOptions_DefaultsTo30SecondsSliding_IfNoEvictionCriteriaIsProvided() { // Arrange var slidingExpiresIn = TimeSpan.FromSeconds(30); var cache = new MemoryCache(new MemoryCacheOptions()); - var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder()); + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()); // Act var cacheEntryOptions = cacheTagHelper.GetMemoryCacheEntryOptions(); @@ -231,7 +277,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // Arrange var expiresAfter = TimeSpan.FromSeconds(42); var cache = new MemoryCache(new MemoryCacheOptions()); - var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { ExpiresAfter = expiresAfter }; @@ -249,7 +295,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // Arrange var expiresSliding = TimeSpan.FromSeconds(37); var cache = new MemoryCache(new MemoryCacheOptions()); - var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { ExpiresSliding = expiresSliding }; @@ -267,7 +313,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // Arrange var priority = CacheItemPriority.High; var cache = new MemoryCache(new MemoryCacheOptions()); - var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { Priority = priority }; @@ -294,7 +340,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1); tagHelperOutput1.PreContent.SetContent(""); tagHelperOutput1.PostContent.SetContent(""); - var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { ViewContext = GetViewContext(), ExpiresAfter = TimeSpan.FromMinutes(10) @@ -315,7 +361,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2); tagHelperOutput2.PreContent.SetContent(""); tagHelperOutput2.PostContent.SetContent(""); - var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { ViewContext = GetViewContext(), ExpiresAfter = TimeSpan.FromMinutes(10) @@ -347,7 +393,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1); tagHelperOutput1.PreContent.SetContent(""); tagHelperOutput1.PostContent.SetContent(""); - var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { ViewContext = GetViewContext(), ExpiresOn = currentTime.AddMinutes(5) @@ -369,7 +415,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2); tagHelperOutput2.PreContent.SetContent(""); tagHelperOutput2.PostContent.SetContent(""); - var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { ViewContext = GetViewContext(), ExpiresOn = currentTime.AddMinutes(5) @@ -400,7 +446,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelperOutput1 = GetTagHelperOutput(childContent: childContent1); tagHelperOutput1.PreContent.SetContent(""); tagHelperOutput1.PostContent.SetContent(""); - var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { ViewContext = GetViewContext(), ExpiresSliding = TimeSpan.FromSeconds(30) @@ -422,7 +468,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelperOutput2 = GetTagHelperOutput(childContent: childContent2); tagHelperOutput2.PreContent.SetContent(""); tagHelperOutput2.PostContent.SetContent(""); - var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { ViewContext = GetViewContext(), ExpiresSliding = TimeSpan.FromSeconds(30) @@ -469,7 +515,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers }); tagHelperOutput.PreContent.SetContent(""); tagHelperOutput.PostContent.SetContent(""); - var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { ViewContext = GetViewContext(), }; @@ -535,13 +581,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers return Task.FromResult(tagHelperContent); }); - var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { ViewContext = GetViewContext(), Enabled = true }; - var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { ViewContext = GetViewContext(), Enabled = true @@ -618,13 +664,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers return Task.FromResult(tagHelperContent); }); - var cacheTagHelper1 = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { ViewContext = GetViewContext(), Enabled = true }; - var cacheTagHelper2 = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { ViewContext = GetViewContext(), Enabled = true @@ -699,7 +745,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelperOutput3 = new TagHelperOutput("cache", new TagHelperAttributeList(), GetChildContentAsync); var tagHelperOutput4 = new TagHelperOutput("cache", new TagHelperAttributeList(), GetChildContentAsync); - var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { ViewContext = GetViewContext(), Enabled = true, @@ -762,13 +808,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var expected = "Hello world"; var cache = new MemoryCache(new MemoryCacheOptions()); var encoder = new HtmlTestEncoder(); - var cacheTagHelper1 = new CacheTagHelper(cache, encoder) + var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), encoder) { ViewContext = GetViewContext(), Enabled = true }; - var cacheTagHelper2 = new CacheTagHelper(cache, encoder) + var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), encoder) { ViewContext = GetViewContext(), Enabled = true @@ -808,7 +854,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // Arrange var expected = new DivideByZeroException(); var cache = new TestMemoryCache(); - var cacheTagHelper = new CacheTagHelper(cache, new HtmlTestEncoder()) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), new HtmlTestEncoder()) { ViewContext = GetViewContext(), Enabled = true @@ -841,7 +887,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var expected = "Hello world"; var cache = new TestMemoryCache(); var encoder = new HtmlTestEncoder(); - var cacheTagHelper = new CacheTagHelper(cache, encoder) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(cache), encoder) { ViewContext = GetViewContext(), Enabled = true diff --git a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/CacheTagKeyTest.cs b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/CacheTagKeyTest.cs index 0b5c083bc6..7cd1718b20 100644 --- a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/CacheTagKeyTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/CacheTagKeyTest.cs @@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.TagHelpers.Cache; +using Microsoft.AspNetCore.Mvc.TagHelpers.Internal; using Microsoft.AspNetCore.Mvc.ViewEngines; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; @@ -29,7 +30,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // Arrange var id = Guid.NewGuid().ToString(); var tagHelperContext = GetTagHelperContext(id); - var cacheTagHelper = new CacheTagHelper(Mock.Of(), new HtmlTestEncoder()) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of()), new HtmlTestEncoder()) { ViewContext = GetViewContext() }; @@ -49,13 +50,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // Arrange var id = Guid.NewGuid().ToString(); var tagHelperContext1 = GetTagHelperContext(id); - var cacheTagHelper1 = new CacheTagHelper(Mock.Of(), new HtmlTestEncoder()) + var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of()), new HtmlTestEncoder()) { ViewContext = GetViewContext() }; var tagHelperContext2 = GetTagHelperContext(id); - var cacheTagHelper2 = new CacheTagHelper(Mock.Of(), new HtmlTestEncoder()) + var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of()), new HtmlTestEncoder()) { ViewContext = GetViewContext() }; @@ -73,13 +74,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { // Arrange var tagHelperContext1 = GetTagHelperContext("some-id"); - var cacheTagHelper1 = new CacheTagHelper(Mock.Of(), new HtmlTestEncoder()) + var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of()), new HtmlTestEncoder()) { ViewContext = GetViewContext() }; var tagHelperContext2 = GetTagHelperContext("some-other-id"); - var cacheTagHelper2 = new CacheTagHelper(Mock.Of(), new HtmlTestEncoder()) + var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of()), new HtmlTestEncoder()) { ViewContext = GetViewContext() }; @@ -97,13 +98,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { // Arrange var tagHelperContext1 = GetTagHelperContext("some-id"); - var cacheTagHelper1 = new CacheTagHelper(Mock.Of(), new HtmlTestEncoder()) + var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of()), new HtmlTestEncoder()) { ViewContext = GetViewContext() }; var tagHelperContext2 = GetTagHelperContext("some-id"); - var cacheTagHelper2 = new CacheTagHelper(Mock.Of(), new HtmlTestEncoder()) + var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of()), new HtmlTestEncoder()) { ViewContext = GetViewContext() }; @@ -124,13 +125,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { // Arrange var tagHelperContext1 = GetTagHelperContext("some-id"); - var cacheTagHelper1 = new CacheTagHelper(Mock.Of(), new HtmlTestEncoder()) + var cacheTagHelper1 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of()), new HtmlTestEncoder()) { ViewContext = GetViewContext() }; var tagHelperContext2 = GetTagHelperContext("some-other-id"); - var cacheTagHelper2 = new CacheTagHelper(Mock.Of(), new HtmlTestEncoder()) + var cacheTagHelper2 = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of()), new HtmlTestEncoder()) { ViewContext = GetViewContext() }; @@ -177,7 +178,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { // Arrange var tagHelperContext = GetTagHelperContext(); - var cacheTagHelper = new CacheTagHelper(Mock.Of(), new HtmlTestEncoder()) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of()), new HtmlTestEncoder()) { ViewContext = GetViewContext(), VaryBy = varyBy @@ -206,7 +207,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { // Arrange var tagHelperContext = GetTagHelperContext(); - var cacheTagHelper = new CacheTagHelper(Mock.Of(), new HtmlTestEncoder()) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of()), new HtmlTestEncoder()) { ViewContext = GetViewContext(), VaryByCookie = varyByCookie @@ -232,7 +233,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { // Arrange var tagHelperContext = GetTagHelperContext(); - var cacheTagHelper = new CacheTagHelper(Mock.Of(), new HtmlTestEncoder()) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of()), new HtmlTestEncoder()) { ViewContext = GetViewContext(), VaryByHeader = varyByHeader @@ -260,7 +261,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { // Arrange var tagHelperContext = GetTagHelperContext(); - var cacheTagHelper = new CacheTagHelper(Mock.Of(), new HtmlTestEncoder()) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of()), new HtmlTestEncoder()) { ViewContext = GetViewContext(), VaryByQuery = varyByQuery @@ -286,7 +287,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { // Arrange var tagHelperContext = GetTagHelperContext(); - var cacheTagHelper = new CacheTagHelper(Mock.Of(), new HtmlTestEncoder()) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of()), new HtmlTestEncoder()) { ViewContext = GetViewContext(), VaryByRoute = varyByRoute @@ -308,7 +309,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // Arrange var expected = "CacheTagHelper||testid||VaryByUser||"; var tagHelperContext = GetTagHelperContext(); - var cacheTagHelper = new CacheTagHelper(Mock.Of(), new HtmlTestEncoder()) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of()), new HtmlTestEncoder()) { ViewContext = GetViewContext(), VaryByUser = true @@ -328,7 +329,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // Arrange var expected = "CacheTagHelper||testid||VaryByUser||test_name"; var tagHelperContext = GetTagHelperContext(); - var cacheTagHelper = new CacheTagHelper(Mock.Of(), new HtmlTestEncoder()) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of()), new HtmlTestEncoder()) { ViewContext = GetViewContext(), VaryByUser = true @@ -351,7 +352,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var expected = "CacheTagHelper||testid||VaryBy||custom-value||" + "VaryByHeader(content-type||text/html)||VaryByUser||someuser"; var tagHelperContext = GetTagHelperContext(); - var cacheTagHelper = new CacheTagHelper(Mock.Of(), new HtmlTestEncoder()) + var cacheTagHelper = new CacheTagHelper(new CacheTagHelperMemoryCacheFactory(Mock.Of()), new HtmlTestEncoder()) { ViewContext = GetViewContext(), VaryByUser = true,