diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs index 236eb88fa2..fa30c8eddd 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs @@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.AspNetCore.Mvc.Razor.Compilation; using Microsoft.AspNetCore.Mvc.Razor.Extensions; +using Microsoft.AspNetCore.Mvc.Razor.Infrastructure; using Microsoft.AspNetCore.Mvc.Razor.Internal; using Microsoft.AspNetCore.Mvc.Razor.TagHelpers; using Microsoft.AspNetCore.Mvc.Rendering; @@ -226,6 +227,7 @@ namespace Microsoft.Extensions.DependencyInjection // Consumed by the Cache tag helper to cache results across the lifetime of the application. services.TryAddSingleton(); + services.TryAddSingleton(); } } } diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Infrastructure/TagHelperMemoryCacheProvider.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Infrastructure/TagHelperMemoryCacheProvider.cs new file mode 100644 index 0000000000..e7deea3326 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Infrastructure/TagHelperMemoryCacheProvider.cs @@ -0,0 +1,23 @@ +// 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; + +namespace Microsoft.AspNetCore.Mvc.Razor.Infrastructure +{ + /// + /// This API supports the MVC's infrastructure and is not intended to be used + /// directly from your code. This API may change in future releases. + /// + public sealed class TagHelperMemoryCacheProvider + { + /// + /// This API supports the MVC's infrastructure and is not intended to be used + /// directly from your code. This API may change in future releases. + /// + public IMemoryCache Cache { get; } = new MemoryCache(new MemoryCacheOptions + { + SizeLimit = 10 * 1024 * 1024 // 10MB + }); + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/ImageTagHelper.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/ImageTagHelper.cs index 587dfc3567..1bf569759d 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/ImageTagHelper.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/ImageTagHelper.cs @@ -4,11 +4,13 @@ using System; using System.Text.Encodings.Web; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Razor.Infrastructure; using Microsoft.AspNetCore.Mvc.Razor.TagHelpers; using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Mvc.TagHelpers.Internal; using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.Mvc.TagHelpers { @@ -36,6 +38,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers /// The . /// The to use. /// The . + [Obsolete("This constructor is obsolete and will be removed in a future version.")] public ImageTagHelper( IHostingEnvironment hostingEnvironment, IMemoryCache cache, @@ -47,6 +50,27 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers Cache = cache; } + /// + /// Creates a new . + /// + /// The . + /// The . + /// The to use. + /// The . + // Decorated with ActivatorUtilitiesConstructor since we want to influence tag helper activation + // to use this constructor in the default case. + [ActivatorUtilitiesConstructor] + public ImageTagHelper( + IHostingEnvironment hostingEnvironment, + TagHelperMemoryCacheProvider cacheProvider, + HtmlEncoder htmlEncoder, + IUrlHelperFactory urlHelperFactory) + : base(urlHelperFactory, htmlEncoder) + { + HostingEnvironment = hostingEnvironment; + Cache = cacheProvider.Cache; + } + /// public override int Order => -1000; @@ -68,9 +92,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers [HtmlAttributeName(AppendVersionAttributeName)] public bool AppendVersion { get; set; } - protected IHostingEnvironment HostingEnvironment { get; } + protected internal IHostingEnvironment HostingEnvironment { get; } - protected IMemoryCache Cache { get; } + protected internal IMemoryCache Cache { get; } /// public override void Process(TagHelperContext context, TagHelperOutput output) diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/FileVersionProvider.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/FileVersionProvider.cs index 19bdf34d09..a369be3189 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/FileVersionProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/FileVersionProvider.cs @@ -69,42 +69,42 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal resolvedPath = path.Substring(0, queryStringOrFragmentStartIndex); } - Uri uri; - if (Uri.TryCreate(resolvedPath, UriKind.Absolute, out uri) && !uri.IsFile) + if (Uri.TryCreate(resolvedPath, UriKind.Absolute, out var uri) && !uri.IsFile) { // Don't append version if the path is absolute. return path; } - string value; - if (!_cache.TryGetValue(path, out value)) + if (_cache.TryGetValue(path, out string value)) { - var cacheEntryOptions = new MemoryCacheEntryOptions(); - cacheEntryOptions.AddExpirationToken(_fileProvider.Watch(resolvedPath)); - var fileInfo = _fileProvider.GetFileInfo(resolvedPath); - - if (!fileInfo.Exists && - _requestPathBase.HasValue && - resolvedPath.StartsWith(_requestPathBase.Value, StringComparison.OrdinalIgnoreCase)) - { - var requestPathBaseRelativePath = resolvedPath.Substring(_requestPathBase.Value.Length); - cacheEntryOptions.AddExpirationToken(_fileProvider.Watch(requestPathBaseRelativePath)); - fileInfo = _fileProvider.GetFileInfo(requestPathBaseRelativePath); - } - - if (fileInfo.Exists) - { - value = QueryHelpers.AddQueryString(path, VersionKey, GetHashForFile(fileInfo)); - } - else - { - // if the file is not in the current server. - value = path; - } - - value = _cache.Set(path, value, cacheEntryOptions); + return value; } + var cacheEntryOptions = new MemoryCacheEntryOptions(); + cacheEntryOptions.AddExpirationToken(_fileProvider.Watch(resolvedPath)); + var fileInfo = _fileProvider.GetFileInfo(resolvedPath); + + if (!fileInfo.Exists && + _requestPathBase.HasValue && + resolvedPath.StartsWith(_requestPathBase.Value, StringComparison.OrdinalIgnoreCase)) + { + var requestPathBaseRelativePath = resolvedPath.Substring(_requestPathBase.Value.Length); + cacheEntryOptions.AddExpirationToken(_fileProvider.Watch(requestPathBaseRelativePath)); + fileInfo = _fileProvider.GetFileInfo(requestPathBaseRelativePath); + } + + if (fileInfo.Exists) + { + value = QueryHelpers.AddQueryString(path, VersionKey, GetHashForFile(fileInfo)); + } + else + { + // if the file is not in the current server. + value = path; + } + + cacheEntryOptions.SetSize(value.Length * sizeof(char)); + value = _cache.Set(path, value, cacheEntryOptions); return value; } diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/GlobbingUrlBuilder.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/GlobbingUrlBuilder.cs index 8464d0bc90..9b756848a1 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/GlobbingUrlBuilder.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/GlobbingUrlBuilder.cs @@ -113,8 +113,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal } var cacheKey = new GlobbingUrlKey(include, exclude); - List files; - if (Cache.TryGetValue(cacheKey, out files)) + if (Cache.TryGetValue(cacheKey, out List files)) { return files; } @@ -148,16 +147,21 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal matcher.AddExcludePatterns(trimmedExcludePatterns); } + var (matchedUrls, sizeInBytes) = FindFiles(matcher); + options.SetSize(sizeInBytes); + return Cache.Set( cacheKey, - FindFiles(matcher), + matchedUrls, options); } - private List FindFiles(Matcher matcher) + private (List matchedUrls, long sizeInBytes) FindFiles(Matcher matcher) { var matches = matcher.Execute(_baseGlobbingDirectory); var matchedUrls = new List(); + var sizeInBytes = 0L; + foreach (var matchedPath in matches.Files) { // Resolve the path to site root @@ -168,10 +172,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal { // Item doesn't already exist. Insert it. matchedUrls.Insert(~index, matchedUrl); + sizeInBytes += matchedUrl.Length * sizeof(char); } } - return matchedUrls; + return (matchedUrls, sizeInBytes); } private class PathComparer : IComparer @@ -231,9 +236,8 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal var result = 0; var xEnumerator = new StringTokenizer(xNoExt, PathSeparator).GetEnumerator(); var yEnumerator = new StringTokenizer(yNoExt, PathSeparator).GetEnumerator(); - StringSegment xSegment; StringSegment ySegment; - while (TryGetNextSegment(ref xEnumerator, out xSegment)) + while (TryGetNextSegment(ref xEnumerator, out var xSegment)) { if (!TryGetNextSegment(ref yEnumerator, out ySegment)) { diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/LinkTagHelper.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/LinkTagHelper.cs index 2d3b8b9456..2b974aebbb 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/LinkTagHelper.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/LinkTagHelper.cs @@ -8,11 +8,13 @@ using System.IO; using System.Text.Encodings.Web; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Html; +using Microsoft.AspNetCore.Mvc.Razor.Infrastructure; using Microsoft.AspNetCore.Mvc.Razor.TagHelpers; using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Mvc.TagHelpers.Internal; using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.Mvc.TagHelpers { @@ -33,7 +35,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers [HtmlTargetElement("link", Attributes = AppendVersionAttributeName, TagStructure = TagStructure.WithoutEndTag)] public class LinkTagHelper : UrlResolutionTagHelper { - private static readonly string FallbackJavaScriptResourceName = typeof(LinkTagHelper).Namespace + ".compiler.resources.LinkTagHelper_FallbackJavaScript.js"; @@ -103,6 +104,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers /// The . /// The . /// The . + [Obsolete("This constructor is obsolete and will be removed in a future version.")] public LinkTagHelper( IHostingEnvironment hostingEnvironment, IMemoryCache cache, @@ -112,8 +114,32 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers : base(urlHelperFactory, htmlEncoder) { HostingEnvironment = hostingEnvironment; - Cache = cache; JavaScriptEncoder = javaScriptEncoder; + Cache = cache; + } + + /// + /// Creates a new . + /// + /// The . + /// + /// The . + /// The . + /// The . + // Decorated with ActivatorUtilitiesConstructor since we want to influence tag helper activation + // to use this constructor in the default case. + [ActivatorUtilitiesConstructor] + public LinkTagHelper( + IHostingEnvironment hostingEnvironment, + TagHelperMemoryCacheProvider cacheProvider, + HtmlEncoder htmlEncoder, + JavaScriptEncoder javaScriptEncoder, + IUrlHelperFactory urlHelperFactory) + : base(urlHelperFactory, htmlEncoder) + { + HostingEnvironment = hostingEnvironment; + JavaScriptEncoder = javaScriptEncoder; + Cache = cacheProvider.Cache; } /// @@ -205,9 +231,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers [HtmlAttributeName(FallbackTestValueAttributeName)] public string FallbackTestValue { get; set; } - protected IHostingEnvironment HostingEnvironment { get; } + protected internal IHostingEnvironment HostingEnvironment { get; } - protected IMemoryCache Cache { get; } + protected internal IMemoryCache Cache { get; } protected JavaScriptEncoder JavaScriptEncoder { get; } diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/ScriptTagHelper.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/ScriptTagHelper.cs index 15f7323db3..d8d6053d20 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/ScriptTagHelper.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/ScriptTagHelper.cs @@ -7,11 +7,14 @@ using System.IO; using System.Text.Encodings.Web; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Html; +using Microsoft.AspNetCore.Mvc.Razor; +using Microsoft.AspNetCore.Mvc.Razor.Infrastructure; using Microsoft.AspNetCore.Mvc.Razor.TagHelpers; using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Mvc.TagHelpers.Internal; using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.DependencyInjection; namespace Microsoft.AspNetCore.Mvc.TagHelpers { @@ -85,6 +88,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers /// The . /// The . /// The . + [Obsolete("This constructor is obsolete and will be removed in a future version.")] public ScriptTagHelper( IHostingEnvironment hostingEnvironment, IMemoryCache cache, @@ -98,6 +102,30 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers JavaScriptEncoder = javaScriptEncoder; } + /// + /// Creates a new . + /// + /// The . + /// The . + /// The . + /// The . + /// The . + // Decorated with ActivatorUtilitiesConstructor since we want to influence tag helper activation + // to use this constructor in the default case. + [ActivatorUtilitiesConstructor] + public ScriptTagHelper( + IHostingEnvironment hostingEnvironment, + TagHelperMemoryCacheProvider cacheProvider, + HtmlEncoder htmlEncoder, + JavaScriptEncoder javaScriptEncoder, + IUrlHelperFactory urlHelperFactory) + : base(urlHelperFactory, htmlEncoder) + { + HostingEnvironment = hostingEnvironment; + Cache = cacheProvider.Cache; + JavaScriptEncoder = javaScriptEncoder; + } + /// public override int Order => -1000; @@ -169,9 +197,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers [HtmlAttributeName(FallbackTestExpressionAttributeName)] public string FallbackTestExpression { get; set; } - protected IHostingEnvironment HostingEnvironment { get; } + protected internal IHostingEnvironment HostingEnvironment { get; } - protected IMemoryCache Cache { get; } + protected internal IMemoryCache Cache { get; private set; } protected JavaScriptEncoder JavaScriptEncoder { get; } diff --git a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ImageTagHelperTest.cs b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ImageTagHelperTest.cs index a2159f251f..f913e6a59b 100644 --- a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ImageTagHelperTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ImageTagHelperTest.cs @@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.Razor.Infrastructure; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Mvc.ViewEngines; @@ -73,7 +74,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new ImageTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), urlHelperFactory.Object) { @@ -127,7 +128,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new ImageTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), MakeUrlHelperFactory()) { @@ -170,7 +171,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); - var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelperFactory()) + var helper = new ImageTagHelper(hostingEnvironment, new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), MakeUrlHelperFactory()) { ViewContext = viewContext, Src = "/images/test-image.png", @@ -206,7 +207,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); - var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelperFactory()) + var helper = new ImageTagHelper(hostingEnvironment, new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), MakeUrlHelperFactory()) { ViewContext = viewContext, Src = "/images/test-image.png", @@ -242,7 +243,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext("/bar"); - var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelperFactory()) + var helper = new ImageTagHelper(hostingEnvironment, new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), MakeUrlHelperFactory()) { ViewContext = viewContext, Src = "/bar/images/image.jpg", @@ -328,8 +329,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers return hostingEnvironment.Object; } - private static IMemoryCache MakeCache() => new MemoryCache(new MemoryCacheOptions()); - private static IUrlHelperFactory MakeUrlHelperFactory() { var urlHelper = new Mock(); diff --git a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/DefaultTagHelperActivatorTest.cs b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/DefaultTagHelperActivatorTest.cs new file mode 100644 index 0000000000..bc6d1238c6 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/DefaultTagHelperActivatorTest.cs @@ -0,0 +1,87 @@ +// 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.Text.Encodings.Web; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.Internal; +using Microsoft.AspNetCore.Mvc.Razor.Infrastructure; +using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.AspNetCore.Mvc.Routing; +using Microsoft.AspNetCore.Mvc.TagHelpers; +using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.Razor.Internal +{ + // Tests to verify that script, link and image tag helper use the size limited instance of MemoryCache. + public class DefaultTagHelperActivatorTest + { + private readonly TagHelperMemoryCacheProvider CacheProvider = new TagHelperMemoryCacheProvider(); + private readonly IMemoryCache MemoryCache = new MemoryCache(new MemoryCacheOptions()); + private readonly IHostingEnvironment HostingEnvironment = Mock.Of(); + + [Fact] + public void ScriptTagHelper_DoesNotUseMemoryCacheInstanceFromDI() + { + // Arrange + var activator = new DefaultTagHelperActivator(new TypeActivatorCache()); + var viewContext = CreateViewContext(); + + var scriptTagHelper = activator.Create(viewContext); + + Assert.Same(CacheProvider.Cache, scriptTagHelper.Cache); + Assert.Same(HostingEnvironment, scriptTagHelper.HostingEnvironment); + } + + [Fact] + public void LinkTagHelper_DoesNotUseMemoryCacheInstanceFromDI() + { + // Arrange + var activator = new DefaultTagHelperActivator(new TypeActivatorCache()); + var viewContext = CreateViewContext(); + + var linkTagHelper = activator.Create(viewContext); + + Assert.Same(CacheProvider.Cache, linkTagHelper.Cache); + Assert.Same(HostingEnvironment, linkTagHelper.HostingEnvironment); + } + + [Fact] + public void ImageTagHelper_DoesNotUseMemoryCacheInstanceFromDI() + { + // Arrange + var activator = new DefaultTagHelperActivator(new TypeActivatorCache()); + var viewContext = CreateViewContext(); + + var imageTagHelper = activator.Create(viewContext); + + Assert.Same(CacheProvider.Cache, imageTagHelper.Cache); + Assert.Same(HostingEnvironment, imageTagHelper.HostingEnvironment); + } + + private ViewContext CreateViewContext() + { + var services = new ServiceCollection() + .AddSingleton(HostingEnvironment) + .AddSingleton(MemoryCache) + .AddSingleton(CacheProvider) + .AddSingleton(HtmlEncoder.Default) + .AddSingleton(JavaScriptEncoder.Default) + .AddSingleton(Mock.Of()) + .BuildServiceProvider(); + + var viewContext = new ViewContext + { + HttpContext = new DefaultHttpContext + { + RequestServices = services, + } + }; + + return viewContext; + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/FileVersionProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/FileVersionProviderTest.cs index 533a38faf3..b2617519ba 100644 --- a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/FileVersionProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/FileVersionProviderTest.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.IO; using System.Text; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Primitives; @@ -267,29 +266,30 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal Assert.Equal("FromCache", result); } - [Theory] - [InlineData("/hello/world", "/hello/world", null)] - [InlineData("/testApp/hello/world", "/hello/world", "/testApp")] - public void SetsValueInCache(string filePath, string watchPath, string requestPathBase) + [Fact] + public void AddFileVersionToPath_CachesEntry() => AddFileVersionToPath("/hello/world", "/hello/world", null); + + [Fact] + public void AddFileVersionToPath_WithRequestPathBase_CachesEntry() => AddFileVersionToPath("/testApp/hello/world", "/hello/world", "/testApp"); + + private static void AddFileVersionToPath(string filePath, string watchPath, string requestPathBase) { // Arrange - var changeToken = new Mock(); + var expected = filePath + "?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk"; + var expectedSize = expected.Length * sizeof(char); + var changeToken = Mock.Of(); + var fileProvider = GetMockFileProvider(filePath, requestPathBase != null); Mock.Get(fileProvider) - .Setup(f => f.Watch(watchPath)).Returns(changeToken.Object); + .Setup(f => f.Watch(watchPath)).Returns(changeToken); - object cacheValue = null; - var value = new Mock(); - value.Setup(c => c.Value).Returns(cacheValue); - value.Setup(c => c.ExpirationTokens).Returns(new List()); + var cacheEntry = Mock.Of(c => c.ExpirationTokens == new List()); var cache = new Mock(); - cache.CallBase = true; - cache.Setup(c => c.TryGetValue(It.IsAny(), out cacheValue)) - .Returns(cacheValue != null); - cache.Setup(c => c.CreateEntry( - /*key*/ filePath)) - .Returns((object key) => value.Object) + + cache.Setup(c => c.CreateEntry(filePath)) + .Returns(cacheEntry) .Verifiable(); + var fileVersionProvider = new FileVersionProvider( fileProvider, cache.Object, @@ -299,7 +299,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal var result = fileVersionProvider.AddFileVersionToPath(filePath); // Assert - Assert.Equal(filePath + "?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", result); + Assert.Equal(expected, result); + Assert.Equal(expected, cacheEntry.Value); + Assert.Equal(expectedSize, cacheEntry.Size); cache.VerifyAll(); } diff --git a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/GlobbingUrlBuilderTest.cs b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/GlobbingUrlBuilderTest.cs index 8493f1daa5..4bce947f96 100644 --- a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/GlobbingUrlBuilderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/GlobbingUrlBuilderTest.cs @@ -411,6 +411,24 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal Assert.Collection(excludePatterns, pattern => Assert.Equal($"{prefix}**/*.min.css", pattern)); } + [Fact] + public void BuildUrlList_AddsToMemoryCache_WithSizeLimit() + { + // Arrange + var cacheEntry = Mock.Of(m => m.ExpirationTokens == new List()); + var cache = Mock.Of(m => m.CreateEntry(It.IsAny()) == cacheEntry); + + var fileProvider = MakeFileProvider(MakeDirectoryContents("site.css", "blank.css")); + var requestPathBase = PathString.Empty; + var globbingUrlBuilder = new GlobbingUrlBuilder(fileProvider, cache, requestPathBase); + + // Act + var urlList = globbingUrlBuilder.BuildUrlList("/site.css", "**/*.css", excludePattern: null); + + // Assert + Assert.Equal(38, cacheEntry.Size); + } + public class FileNode { public FileNode(string name) diff --git a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/LinkTagHelperTest.cs b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/LinkTagHelperTest.cs index 833da15fc4..309371a185 100644 --- a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/LinkTagHelperTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/LinkTagHelperTest.cs @@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.Razor.Infrastructure; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Mvc.TagHelpers.Internal; @@ -70,7 +71,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new LinkTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), urlHelperFactory.Object) @@ -167,7 +168,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new LinkTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -330,7 +331,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new LinkTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -427,7 +428,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new LinkTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -473,7 +474,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new LinkTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -584,7 +585,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new LinkTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -614,7 +615,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new LinkTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -660,7 +661,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new LinkTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -723,7 +724,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new LinkTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -764,7 +765,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new LinkTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -802,7 +803,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new LinkTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -860,7 +861,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new LinkTagHelper( MakeHostingEnvironment(), - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -939,7 +940,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new LinkTagHelper( MakeHostingEnvironment(), - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -991,7 +992,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new LinkTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -1084,8 +1085,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers return hostingEnvironment.Object; } - private static IMemoryCache MakeCache() => new MemoryCache(new MemoryCacheOptions()); - private static IUrlHelperFactory MakeUrlHelperFactory() { var urlHelper = new Mock(); diff --git a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs index 923a76b889..eb6696292a 100644 --- a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs @@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.Razor.Infrastructure; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Mvc.TagHelpers.Internal; @@ -71,7 +72,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new ScriptTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), urlHelperFactory.Object) @@ -118,7 +119,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new ScriptTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -311,7 +312,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new ScriptTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -408,7 +409,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new ScriptTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -507,7 +508,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new ScriptTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -536,7 +537,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new ScriptTagHelper( MakeHostingEnvironment(), - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -581,7 +582,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new ScriptTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -625,7 +626,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new ScriptTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -688,7 +689,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new ScriptTagHelper( hostingEnvironment, - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -726,7 +727,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new ScriptTagHelper( MakeHostingEnvironment(), - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -760,7 +761,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new ScriptTagHelper( MakeHostingEnvironment(), - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -796,7 +797,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new ScriptTagHelper( MakeHostingEnvironment(), - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -859,7 +860,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new ScriptTagHelper( MakeHostingEnvironment(), - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -907,7 +908,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var helper = new ScriptTagHelper( MakeHostingEnvironment(), - MakeCache(), + new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), MakeUrlHelperFactory()) @@ -997,8 +998,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers return hostingEnvironment.Object; } - private static IMemoryCache MakeCache() => new MemoryCache(new MemoryCacheOptions()); - private static IUrlHelperFactory MakeUrlHelperFactory() { var urlHelper = new Mock();