From 4b83f7b510f22ea4acd7e383fd483301c77f5fec Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 13 Sep 2018 10:06:01 -0700 Subject: [PATCH] Make FileVersionProvider repleacable Fixes #6371 --- .../MvcRazorMvcCoreBuilderExtensions.cs | 4 +- .../Infrastructure}/CryptographyAlgorithms.cs | 4 +- .../DefaultFileVersionProvider.cs} | 67 ++--- .../TagHelperMemoryCacheProvider.cs | 2 +- .../Properties/AssemblyInfo.cs | 2 + .../Cache/CacheTagKey.cs | 1 + .../ImageTagHelper.cs | 18 +- .../LinkTagHelper.cs | 21 +- .../ScriptTagHelper.cs | 20 +- .../ViewFeatures/IFileVersionProvider.cs | 21 ++ ...t.cs => DefaultFileVersionProviderTest.cs} | 125 ++++---- .../ImageTagHelperTest.cs | 81 +++-- .../Internal/DefaultTagHelperActivatorTest.cs | 6 + .../LinkTagHelperTest.cs | 284 ++++++------------ .../ScriptTagHelperTest.cs | 257 +++++----------- 15 files changed, 350 insertions(+), 563 deletions(-) rename src/{Microsoft.AspNetCore.Mvc.TagHelpers/Internal => Microsoft.AspNetCore.Mvc.Razor/Infrastructure}/CryptographyAlgorithms.cs (88%) rename src/{Microsoft.AspNetCore.Mvc.TagHelpers/Internal/FileVersionProvider.cs => Microsoft.AspNetCore.Mvc.Razor/Infrastructure/DefaultFileVersionProvider.cs} (51%) create mode 100644 src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/IFileVersionProvider.cs rename test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/{Internal/FileVersionProviderTest.cs => DefaultFileVersionProviderTest.cs} (78%) diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs index 7ede8232f4..131bc13391 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs @@ -14,6 +14,7 @@ using Microsoft.AspNetCore.Mvc.Razor.Infrastructure; using Microsoft.AspNetCore.Mvc.Razor.Internal; using Microsoft.AspNetCore.Mvc.Razor.TagHelpers; using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.Extensions.Caching.Memory; @@ -228,9 +229,10 @@ namespace Microsoft.Extensions.DependencyInjection // TagHelperComponents manager services.TryAddScoped(); - // Consumed by the Cache tag helper to cache results across the lifetime of the application. + // Infrastructure for MVC TagHelpers services.TryAddSingleton(); services.TryAddSingleton(); + services.TryAddSingleton(); } } } diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/CryptographyAlgorithms.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Infrastructure/CryptographyAlgorithms.cs similarity index 88% rename from src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/CryptographyAlgorithms.cs rename to src/Microsoft.AspNetCore.Mvc.Razor/Infrastructure/CryptographyAlgorithms.cs index 02c28552e1..2442315477 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/CryptographyAlgorithms.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Infrastructure/CryptographyAlgorithms.cs @@ -3,9 +3,9 @@ using System.Security.Cryptography; -namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal +namespace Microsoft.AspNetCore.Mvc.Razor.Infrastructure { - public static class CryptographyAlgorithms + internal static class CryptographyAlgorithms { public static SHA256 CreateSHA256() { diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/FileVersionProvider.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Infrastructure/DefaultFileVersionProvider.cs similarity index 51% rename from src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/FileVersionProvider.cs rename to src/Microsoft.AspNetCore.Mvc.Razor/Infrastructure/DefaultFileVersionProvider.cs index a369be3189..ae4bd7c1a6 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/Internal/FileVersionProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Infrastructure/DefaultFileVersionProvider.cs @@ -2,59 +2,46 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.FileProviders; -namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal +namespace Microsoft.AspNetCore.Mvc.Razor.Infrastructure { /// /// Provides version hash for a specified file. /// - public class FileVersionProvider + internal class DefaultFileVersionProvider : IFileVersionProvider { private const string VersionKey = "v"; private static readonly char[] QueryStringAndFragmentTokens = new [] { '?', '#' }; - private readonly IFileProvider _fileProvider; - private readonly IMemoryCache _cache; - private readonly PathString _requestPathBase; - /// - /// Creates a new instance of . - /// - /// The file provider to get and watch files. - /// where versioned urls of files are cached. - /// The base path for the current HTTP request. - public FileVersionProvider( - IFileProvider fileProvider, - IMemoryCache cache, - PathString requestPathBase) + public DefaultFileVersionProvider( + IHostingEnvironment hostingEnvironment, + TagHelperMemoryCacheProvider cacheProvider) { - if (fileProvider == null) + if (hostingEnvironment == null) { - throw new ArgumentNullException(nameof(fileProvider)); + throw new ArgumentNullException(nameof(hostingEnvironment)); } - if (cache == null) + if (cacheProvider == null) { - throw new ArgumentNullException(nameof(cache)); + throw new ArgumentNullException(nameof(cacheProvider)); } - _fileProvider = fileProvider; - _cache = cache; - _requestPathBase = requestPathBase; + FileProvider = hostingEnvironment.WebRootFileProvider; + Cache = cacheProvider.Cache; } - /// - /// Adds version query parameter to the specified file path. - /// - /// The path of the file to which version should be added. - /// Path containing the version query string. - /// - /// The version query string is appended with the key "v". - /// - public string AddFileVersionToPath(string path) + public IFileProvider FileProvider { get; } + + public IMemoryCache Cache { get; } + + public string AddFileVersionToPath(PathString requestPathBase, string path) { if (path == null) { @@ -75,22 +62,22 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal return path; } - if (_cache.TryGetValue(path, out string value)) + if (Cache.TryGetValue(path, out string value)) { return value; } var cacheEntryOptions = new MemoryCacheEntryOptions(); - cacheEntryOptions.AddExpirationToken(_fileProvider.Watch(resolvedPath)); - var fileInfo = _fileProvider.GetFileInfo(resolvedPath); + cacheEntryOptions.AddExpirationToken(FileProvider.Watch(resolvedPath)); + var fileInfo = FileProvider.GetFileInfo(resolvedPath); if (!fileInfo.Exists && - _requestPathBase.HasValue && - resolvedPath.StartsWith(_requestPathBase.Value, StringComparison.OrdinalIgnoreCase)) + requestPathBase.HasValue && + resolvedPath.StartsWith(requestPathBase.Value, StringComparison.OrdinalIgnoreCase)) { - var requestPathBaseRelativePath = resolvedPath.Substring(_requestPathBase.Value.Length); - cacheEntryOptions.AddExpirationToken(_fileProvider.Watch(requestPathBaseRelativePath)); - fileInfo = _fileProvider.GetFileInfo(requestPathBaseRelativePath); + var requestPathBaseRelativePath = resolvedPath.Substring(requestPathBase.Value.Length); + cacheEntryOptions.AddExpirationToken(FileProvider.Watch(requestPathBaseRelativePath)); + fileInfo = FileProvider.GetFileInfo(requestPathBaseRelativePath); } if (fileInfo.Exists) @@ -104,7 +91,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal } cacheEntryOptions.SetSize(value.Length * sizeof(char)); - value = _cache.Set(path, value, cacheEntryOptions); + value = Cache.Set(path, value, cacheEntryOptions); return value; } diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Infrastructure/TagHelperMemoryCacheProvider.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Infrastructure/TagHelperMemoryCacheProvider.cs index e7deea3326..c80b9850c7 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Infrastructure/TagHelperMemoryCacheProvider.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Infrastructure/TagHelperMemoryCacheProvider.cs @@ -15,7 +15,7 @@ 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 IMemoryCache Cache { get; } = new MemoryCache(new MemoryCacheOptions + public IMemoryCache Cache { get; internal set; } = new MemoryCache(new MemoryCacheOptions { SizeLimit = 10 * 1024 * 1024 // 10MB }); diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Properties/AssemblyInfo.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Properties/AssemblyInfo.cs index 73c4c5a356..0e1a8e8695 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Properties/AssemblyInfo.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Properties/AssemblyInfo.cs @@ -4,7 +4,9 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.RazorPages, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.TagHelpers, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] [assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.RazorPages.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.TagHelpers.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/Cache/CacheTagKey.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/Cache/CacheTagKey.cs index 00647c6e2f..6db23cdcee 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/Cache/CacheTagKey.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/Cache/CacheTagKey.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Globalization; using System.Text; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.Razor.Infrastructure; using Microsoft.AspNetCore.Mvc.TagHelpers.Internal; using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Routing; diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/ImageTagHelper.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/ImageTagHelper.cs index 1bf569759d..97989b7754 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/ImageTagHelper.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/ImageTagHelper.cs @@ -7,7 +7,7 @@ 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.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; @@ -29,8 +29,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers private const string AppendVersionAttributeName = "asp-append-version"; private const string SrcAttributeName = "src"; - private FileVersionProvider _fileVersionProvider; - /// /// Creates a new . /// @@ -55,6 +53,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers /// /// The . /// The . + /// The . /// The to use. /// The . // Decorated with ActivatorUtilitiesConstructor since we want to influence tag helper activation @@ -63,12 +62,14 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers public ImageTagHelper( IHostingEnvironment hostingEnvironment, TagHelperMemoryCacheProvider cacheProvider, + IFileVersionProvider fileVersionProvider, HtmlEncoder htmlEncoder, IUrlHelperFactory urlHelperFactory) : base(urlHelperFactory, htmlEncoder) { HostingEnvironment = hostingEnvironment; Cache = cacheProvider.Cache; + FileVersionProvider = fileVersionProvider; } /// @@ -96,6 +97,8 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers protected internal IMemoryCache Cache { get; } + internal IFileVersionProvider FileVersionProvider { get; private set; } + /// public override void Process(TagHelperContext context, TagHelperOutput output) { @@ -121,18 +124,15 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // not function properly. Src = output.Attributes[SrcAttributeName].Value as string; - output.Attributes.SetAttribute(SrcAttributeName, _fileVersionProvider.AddFileVersionToPath(Src)); + output.Attributes.SetAttribute(SrcAttributeName, FileVersionProvider.AddFileVersionToPath(ViewContext.HttpContext.Request.PathBase, Src)); } } private void EnsureFileVersionProvider() { - if (_fileVersionProvider == null) + if (FileVersionProvider == null) { - _fileVersionProvider = new FileVersionProvider( - HostingEnvironment.WebRootFileProvider, - Cache, - ViewContext.HttpContext.Request.PathBase); + FileVersionProvider = ViewContext.HttpContext.RequestServices.GetRequiredService(); } } } diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/LinkTagHelper.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/LinkTagHelper.cs index 2b974aebbb..d58aee8711 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/LinkTagHelper.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/LinkTagHelper.cs @@ -12,6 +12,7 @@ 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.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; @@ -53,8 +54,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers private const string IntegrityAttributeName = "integrity"; private static readonly Func Compare = (a, b) => a - b; - private FileVersionProvider _fileVersionProvider; - private static readonly ModeAttributes[] ModeDetails = new[] { // Regular src with file version alone new ModeAttributes(Mode.AppendVersion, new[] { AppendVersionAttributeName }), @@ -123,6 +122,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers /// /// The . /// + /// The . /// The . /// The . /// The . @@ -132,6 +132,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers public LinkTagHelper( IHostingEnvironment hostingEnvironment, TagHelperMemoryCacheProvider cacheProvider, + IFileVersionProvider fileVersionProvider, HtmlEncoder htmlEncoder, JavaScriptEncoder javaScriptEncoder, IUrlHelperFactory urlHelperFactory) @@ -140,6 +141,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers HostingEnvironment = hostingEnvironment; JavaScriptEncoder = javaScriptEncoder; Cache = cacheProvider.Cache; + FileVersionProvider = fileVersionProvider; } /// @@ -242,6 +244,8 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers protected internal GlobbingUrlBuilder GlobbingUrlBuilder { get; set; } #pragma warning restore PUB0001 + internal IFileVersionProvider FileVersionProvider { get; private set; } + // Shared writer for determining the string content of a TagHelperAttribute's Value. private StringWriter StringWriter { @@ -299,7 +303,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var existingAttribute = output.Attributes[index]; output.Attributes[index] = new TagHelperAttribute( existingAttribute.Name, - _fileVersionProvider.AddFileVersionToPath(Href), + FileVersionProvider.AddFileVersionToPath(ViewContext.HttpContext.Request.PathBase, Href), existingAttribute.ValueStyle); } } @@ -468,7 +472,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var valueToWrite = fallbackHrefs[i]; if (AppendVersion == true) { - valueToWrite = _fileVersionProvider.AddFileVersionToPath(fallbackHrefs[i]); + valueToWrite = FileVersionProvider.AddFileVersionToPath(ViewContext.HttpContext.Request.PathBase, fallbackHrefs[i]); } // Must HTML-encode the href attribute value to ensure the written element is valid. Must also @@ -495,12 +499,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers private void EnsureFileVersionProvider() { - if (_fileVersionProvider == null) + if (FileVersionProvider == null) { - _fileVersionProvider = new FileVersionProvider( - HostingEnvironment.WebRootFileProvider, - Cache, - ViewContext.HttpContext.Request.PathBase); + FileVersionProvider = ViewContext.HttpContext.RequestServices.GetRequiredService(); } } @@ -540,7 +541,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { if (AppendVersion == true) { - hrefValue = _fileVersionProvider.AddFileVersionToPath(hrefValue); + hrefValue = FileVersionProvider.AddFileVersionToPath(ViewContext.HttpContext.Request.PathBase, hrefValue); } builder diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/ScriptTagHelper.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/ScriptTagHelper.cs index d8d6053d20..c9b217c1da 100644 --- a/src/Microsoft.AspNetCore.Mvc.TagHelpers/ScriptTagHelper.cs +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/ScriptTagHelper.cs @@ -7,11 +7,11 @@ 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.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; @@ -44,7 +44,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers private const string IntegrityAttributeName = "integrity"; private const string AppendVersionAttributeName = "asp-append-version"; private static readonly Func Compare = (a, b) => a - b; - private FileVersionProvider _fileVersionProvider; private StringWriter _stringWriter; private static readonly ModeAttributes[] ModeDetails = new[] { @@ -107,6 +106,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers /// /// The . /// The . + /// The . /// The . /// The . /// The . @@ -116,6 +116,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers public ScriptTagHelper( IHostingEnvironment hostingEnvironment, TagHelperMemoryCacheProvider cacheProvider, + IFileVersionProvider fileVersionProvider, HtmlEncoder htmlEncoder, JavaScriptEncoder javaScriptEncoder, IUrlHelperFactory urlHelperFactory) @@ -124,6 +125,8 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers HostingEnvironment = hostingEnvironment; Cache = cacheProvider.Cache; JavaScriptEncoder = javaScriptEncoder; + + FileVersionProvider = fileVersionProvider; } /// @@ -201,6 +204,8 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers protected internal IMemoryCache Cache { get; private set; } + internal IFileVersionProvider FileVersionProvider { get; private set; } + protected JavaScriptEncoder JavaScriptEncoder { get; } // Internal for ease of use when testing. @@ -265,7 +270,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var existingAttribute = output.Attributes[index]; output.Attributes[index] = new TagHelperAttribute( existingAttribute.Name, - _fileVersionProvider.AddFileVersionToPath(Src), + FileVersionProvider.AddFileVersionToPath(ViewContext.HttpContext.Request.PathBase, Src), existingAttribute.ValueStyle); } } @@ -383,7 +388,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { if (AppendVersion == true) { - srcValue = _fileVersionProvider.AddFileVersionToPath(srcValue); + srcValue = FileVersionProvider.AddFileVersionToPath(ViewContext.HttpContext.Request.PathBase, srcValue); } return srcValue; @@ -428,12 +433,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers private void EnsureFileVersionProvider() { - if (_fileVersionProvider == null) + if (FileVersionProvider == null) { - _fileVersionProvider = new FileVersionProvider( - HostingEnvironment.WebRootFileProvider, - Cache, - ViewContext.HttpContext.Request.PathBase); + FileVersionProvider = ViewContext.HttpContext.RequestServices.GetRequiredService(); } } diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/IFileVersionProvider.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/IFileVersionProvider.cs new file mode 100644 index 0000000000..1aa918c30f --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/ViewFeatures/IFileVersionProvider.cs @@ -0,0 +1,21 @@ +// 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.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Mvc.ViewFeatures +{ + /// + /// Provides version hash for a specified file. + /// + public interface IFileVersionProvider + { + /// + /// Adds version query parameter to the specified file path. + /// + /// The base path for the current HTTP request. + /// The path of the file to which version should be added. + /// Path containing the version query string. + string AddFileVersionToPath(PathString requestPathBase, string path); + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/FileVersionProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/DefaultFileVersionProviderTest.cs similarity index 78% rename from test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/FileVersionProviderTest.cs rename to test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/DefaultFileVersionProviderTest.cs index b2617519ba..9446703636 100644 --- a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/FileVersionProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/DefaultFileVersionProviderTest.cs @@ -4,16 +4,18 @@ using System.Collections.Generic; using System.IO; using System.Text; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.Razor.Infrastructure; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Primitives; using Moq; using Xunit; -namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal +namespace Microsoft.AspNetCore.Mvc.TagHelpers { - public class FileVersionProviderTest + public class DefaultFileVersionProviderTest { [Theory] [InlineData("/hello/world", "/hello/world?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk")] @@ -25,13 +27,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal { // Arrange var fileProvider = GetMockFileProvider(filePath); - var fileVersionProvider = new FileVersionProvider( - fileProvider, - new MemoryCache(new MemoryCacheOptions()), - GetRequestPathBase()); + var fileVersionProvider = GetFileVersionProvider(fileProvider); + var requestPath = GetRequestPathBase(); // Act - var result = fileVersionProvider.AddFileVersionToPath(filePath); + var result = fileVersionProvider.AddFileVersionToPath(requestPath, filePath); // Assert Assert.Equal(expected, result); @@ -46,14 +46,12 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal path, pathStartsWithAppName: false, fileDoesNotExist: true); - var fileVersionProvider = new FileVersionProvider( - fileProvider, - new MemoryCache(new MemoryCacheOptions()), - GetRequestPathBase()); + var fileVersionProvider = GetFileVersionProvider(fileProvider); var mockFileProvider = Mock.Get(fileProvider); + var requestPath = GetRequestPathBase(); // Act 1 - var result = fileVersionProvider.AddFileVersionToPath(path); + var result = fileVersionProvider.AddFileVersionToPath(requestPath, path); // Assert 1 Assert.Equal(path, result); @@ -61,7 +59,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal mockFileProvider.Verify(f => f.Watch(It.IsAny()), Times.Once()); // Act 2 - result = fileVersionProvider.AddFileVersionToPath(path); + result = fileVersionProvider.AddFileVersionToPath(requestPath, path); // Assert 2 Assert.Equal(path, result); @@ -78,14 +76,12 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal var fileProvider = GetMockFileProvider( "file.txt", pathStartsWithAppName); - var fileVersionProvider = new FileVersionProvider( - fileProvider, - new MemoryCache(new MemoryCacheOptions()), - GetRequestPathBase()); + var fileVersionProvider = GetFileVersionProvider(fileProvider); var mockFileProvider = Mock.Get(fileProvider); + var requestPath = GetRequestPathBase(); // Act 1 - var result = fileVersionProvider.AddFileVersionToPath(path); + var result = fileVersionProvider.AddFileVersionToPath(requestPath, path); // Assert 1 Assert.Equal($"{path}?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", result); @@ -93,7 +89,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal mockFileProvider.Verify(f => f.Watch(It.IsAny()), Times.Once()); // Act 2 - result = fileVersionProvider.AddFileVersionToPath(path); + result = fileVersionProvider.AddFileVersionToPath(requestPath, path); // Assert 2 Assert.Equal($"{path}?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", result); @@ -106,13 +102,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal { // Arrange var fileProvider = new TestFileProvider(); - var fileVersionProvider = new FileVersionProvider( - fileProvider, - new MemoryCache(new MemoryCacheOptions()), - GetRequestPathBase()); + var fileVersionProvider = GetFileVersionProvider(fileProvider); + var requestPath = GetRequestPathBase(); // Act 1 - File does not exist - var result = fileVersionProvider.AddFileVersionToPath("file.txt"); + var result = fileVersionProvider.AddFileVersionToPath(requestPath, "file.txt"); // Assert 1 Assert.Equal("file.txt", result); @@ -120,7 +114,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal // Act 2 - File gets added fileProvider.AddFile("file.txt", "Hello World!"); fileProvider.GetChangeToken("file.txt").HasChanged = true; - result = fileVersionProvider.AddFileVersionToPath("file.txt"); + result = fileVersionProvider.AddFileVersionToPath(requestPath, "file.txt"); // Assert 2 Assert.Equal("file.txt?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", result); @@ -131,14 +125,12 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal { // Arrange var fileProvider = new TestFileProvider(); - var fileVersionProvider = new FileVersionProvider( - fileProvider, - new MemoryCache(new MemoryCacheOptions()), - GetRequestPathBase()); + var requestPath = GetRequestPathBase(); + var fileVersionProvider = GetFileVersionProvider(fileProvider); fileProvider.AddFile("file.txt", "Hello World!"); // Act 1 - File exists - var result = fileVersionProvider.AddFileVersionToPath("file.txt"); + var result = fileVersionProvider.AddFileVersionToPath(requestPath, "file.txt"); // Assert 1 Assert.Equal("file.txt?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", result); @@ -146,7 +138,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal // Act 2 fileProvider.DeleteFile("file.txt"); fileProvider.GetChangeToken("file.txt").HasChanged = true; - result = fileVersionProvider.AddFileVersionToPath("file.txt"); + result = fileVersionProvider.AddFileVersionToPath(requestPath, "file.txt"); // Assert 2 Assert.Equal("file.txt", result); @@ -157,14 +149,12 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal { // Arrange var fileProvider = new TestFileProvider(); - var fileVersionProvider = new FileVersionProvider( - fileProvider, - new MemoryCache(new MemoryCacheOptions()), - GetRequestPathBase("/wwwroot/")); + var requestPath = GetRequestPathBase("/wwwroot/"); + var fileVersionProvider = GetFileVersionProvider(fileProvider); fileProvider.AddFile("file.txt", "Hello World!"); // Act 1 - File exists - var result = fileVersionProvider.AddFileVersionToPath("/wwwroot/file.txt"); + var result = fileVersionProvider.AddFileVersionToPath(requestPath, "/wwwroot/file.txt"); // Assert 1 Assert.Equal("/wwwroot/file.txt?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", result); @@ -172,7 +162,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal // Act 2 fileProvider.DeleteFile("file.txt"); fileProvider.GetChangeToken("file.txt").HasChanged = true; - result = fileVersionProvider.AddFileVersionToPath("/wwwroot/file.txt"); + result = fileVersionProvider.AddFileVersionToPath(requestPath, "/wwwroot/file.txt"); // Assert 2 Assert.Equal("/wwwroot/file.txt", result); @@ -192,14 +182,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal var fileProvider = new TestFileProvider(); fileProvider.AddFile("/hello/world", mockFile.Object); - - var fileVersionProvider = new FileVersionProvider( - fileProvider, - new MemoryCache(new MemoryCacheOptions()), - GetRequestPathBase()); + var requestPath = GetRequestPathBase(); + var fileVersionProvider = GetFileVersionProvider(fileProvider); // Act - var result = fileVersionProvider.AddFileVersionToPath("/hello/world"); + var result = fileVersionProvider.AddFileVersionToPath(requestPath, "/hello/world"); // Assert Assert.True(stream.Disposed); @@ -216,13 +203,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal { // Arrange var fileProvider = GetMockFileProvider(filePath, pathStartsWithAppBase); - var fileVersionProvider = new FileVersionProvider( - fileProvider, - new MemoryCache(new MemoryCacheOptions()), - GetRequestPathBase(requestPathBase)); + var requestPath = GetRequestPathBase(requestPathBase); + var fileVersionProvider = GetFileVersionProvider(fileProvider); // Act - var result = fileVersionProvider.AddFileVersionToPath(filePath); + var result = fileVersionProvider.AddFileVersionToPath(requestPath, filePath); // Assert Assert.Equal(filePath + "?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", result); @@ -234,13 +219,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal // Arrange var filePath = "http://contoso.com/hello/world"; var fileProvider = GetMockFileProvider(filePath, false, true); - var fileVersionProvider = new FileVersionProvider( - fileProvider, - new MemoryCache(new MemoryCacheOptions()), - GetRequestPathBase()); + var requestPath = GetRequestPathBase(); + var fileVersionProvider = GetFileVersionProvider(fileProvider); // Act - var result = fileVersionProvider.AddFileVersionToPath(filePath); + var result = fileVersionProvider.AddFileVersionToPath(requestPath, filePath); // Assert Assert.Equal("http://contoso.com/hello/world", result); @@ -252,15 +235,14 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal // Arrange var filePath = "/hello/world"; var fileProvider = GetMockFileProvider(filePath); - var memoryCache = new MemoryCache(new MemoryCacheOptions()); - memoryCache.Set(filePath, "FromCache"); - var fileVersionProvider = new FileVersionProvider( - fileProvider, - memoryCache, - GetRequestPathBase()); + var fileVersionProvider = GetFileVersionProvider(fileProvider); + var cacheEntryOptions = new MemoryCacheEntryOptions(); + cacheEntryOptions.SetSize(1); + fileVersionProvider.Cache.Set(filePath, "FromCache", cacheEntryOptions); + var requestPath = GetRequestPathBase(); // Act - var result = fileVersionProvider.AddFileVersionToPath(filePath); + var result = fileVersionProvider.AddFileVersionToPath(requestPath, filePath); // Assert Assert.Equal("FromCache", result); @@ -290,13 +272,12 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal .Returns(cacheEntry) .Verifiable(); - var fileVersionProvider = new FileVersionProvider( - fileProvider, - cache.Object, - GetRequestPathBase(requestPathBase)); + var requestPath = GetRequestPathBase(requestPathBase); + + var fileVersionProvider = GetFileVersionProvider(fileProvider, cache.Object); // Act - var result = fileVersionProvider.AddFileVersionToPath(filePath); + var result = fileVersionProvider.AddFileVersionToPath(requestPath, filePath); // Assert Assert.Equal(expected, result); @@ -305,6 +286,20 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Internal cache.VerifyAll(); } + private static DefaultFileVersionProvider GetFileVersionProvider( + IFileProvider fileProvider, + IMemoryCache memoryCache = null) + { + var hostingEnv = Mock.Of(e => e.WebRootFileProvider == fileProvider); + var cacheProvider = new TagHelperMemoryCacheProvider(); + if (memoryCache != null) + { + cacheProvider.Cache = memoryCache; + } + + return new DefaultFileVersionProvider(hostingEnv, cacheProvider); + } + private static IFileProvider GetMockFileProvider( string filePath, bool pathStartsWithAppName = false, diff --git a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ImageTagHelperTest.cs b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ImageTagHelperTest.cs index b3787dccec..1c8a307c4a 100644 --- a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ImageTagHelperTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ImageTagHelperTest.cs @@ -19,7 +19,6 @@ using Microsoft.AspNetCore.Mvc.ViewEngines; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Primitives; using Microsoft.Extensions.WebEncoders.Testing; @@ -58,8 +57,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers outputAttributes, getChildContentAsync: (useCachedResult, encoder) => Task.FromResult( new DefaultTagHelperContent())); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); var urlHelper = new Mock(); // Ensure expanded path does not look like an absolute path on Linux, avoiding @@ -72,16 +69,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers .Setup(f => f.GetUrlHelper(It.IsAny())) .Returns(urlHelper.Object); - var helper = new ImageTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - urlHelperFactory.Object) - { - ViewContext = viewContext, - AppendVersion = true, - Src = src, - }; + var helper = GetHelper(urlHelperFactory: urlHelperFactory.Object); + helper.AppendVersion = true; + helper.Src = src; // Act helper.Process(context, output); @@ -123,19 +113,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { "src", "testimage.png?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk" } }); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); - - var helper = new ImageTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - MakeUrlHelperFactory()) - { - ViewContext = viewContext, - Src = "testimage.png", - AppendVersion = true, - }; + var helper = GetHelper(); + helper.Src = "testimage.png"; + helper.AppendVersion = true; // Act helper.Process(context, output); @@ -171,12 +151,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); - var helper = new ImageTagHelper(hostingEnvironment, new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), MakeUrlHelperFactory()) - { - ViewContext = viewContext, - Src = "/images/test-image.png", - AppendVersion = true - }; + var helper = GetHelper(); + helper.Src = "/images/test-image.png"; + helper.AppendVersion = true; // Act helper.Process(context, output); @@ -207,12 +184,8 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); - var helper = new ImageTagHelper(hostingEnvironment, new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), MakeUrlHelperFactory()) - { - ViewContext = viewContext, - Src = "/images/test-image.png", - AppendVersion = false - }; + var helper = GetHelper(); + helper.Src = "/images/test-image.png"; // Act helper.Process(context, output); @@ -243,12 +216,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext("/bar"); - var helper = new ImageTagHelper(hostingEnvironment, new TagHelperMemoryCacheProvider(), new HtmlTestEncoder(), MakeUrlHelperFactory()) - { - ViewContext = viewContext, - Src = "/bar/images/image.jpg", - AppendVersion = true - }; + var helper = GetHelper(); + helper.Src = "/bar/images/image.jpg"; + helper.AppendVersion = true; // Act helper.Process(context, output); @@ -281,6 +251,29 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers return viewContext; } + private static ImageTagHelper GetHelper( + IHostingEnvironment hostingEnvironment = null, + IUrlHelperFactory urlHelperFactory = null, + ViewContext viewContext = null) + { + hostingEnvironment = hostingEnvironment ?? MakeHostingEnvironment(); + urlHelperFactory = urlHelperFactory ?? MakeUrlHelperFactory(); + viewContext = viewContext ?? MakeViewContext(); + + var cacheProvider = new TagHelperMemoryCacheProvider(); + var fileVersionProvider = new DefaultFileVersionProvider(hostingEnvironment, cacheProvider); + + return new ImageTagHelper( + hostingEnvironment, + new TagHelperMemoryCacheProvider(), + fileVersionProvider, + new HtmlTestEncoder(), + urlHelperFactory) + { + ViewContext = viewContext, + }; + } + private static TagHelperContext MakeTagHelperContext( TagHelperAttributeList attributes) { diff --git a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/DefaultTagHelperActivatorTest.cs b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/DefaultTagHelperActivatorTest.cs index bc6d1238c6..ad85133eee 100644 --- a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/DefaultTagHelperActivatorTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/Internal/DefaultTagHelperActivatorTest.cs @@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Mvc.Razor.Infrastructure; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Mvc.TagHelpers; +using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Moq; @@ -22,6 +23,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal private readonly TagHelperMemoryCacheProvider CacheProvider = new TagHelperMemoryCacheProvider(); private readonly IMemoryCache MemoryCache = new MemoryCache(new MemoryCacheOptions()); private readonly IHostingEnvironment HostingEnvironment = Mock.Of(); + private readonly IFileVersionProvider FileVersionProvider = Mock.Of(); [Fact] public void ScriptTagHelper_DoesNotUseMemoryCacheInstanceFromDI() @@ -34,6 +36,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal Assert.Same(CacheProvider.Cache, scriptTagHelper.Cache); Assert.Same(HostingEnvironment, scriptTagHelper.HostingEnvironment); + Assert.Same(FileVersionProvider, scriptTagHelper.FileVersionProvider); } [Fact] @@ -47,6 +50,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal Assert.Same(CacheProvider.Cache, linkTagHelper.Cache); Assert.Same(HostingEnvironment, linkTagHelper.HostingEnvironment); + Assert.Same(FileVersionProvider, linkTagHelper.FileVersionProvider); } [Fact] @@ -60,6 +64,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal Assert.Same(CacheProvider.Cache, imageTagHelper.Cache); Assert.Same(HostingEnvironment, imageTagHelper.HostingEnvironment); + Assert.Same(FileVersionProvider, imageTagHelper.FileVersionProvider); } private ViewContext CreateViewContext() @@ -71,6 +76,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal .AddSingleton(HtmlEncoder.Default) .AddSingleton(JavaScriptEncoder.Default) .AddSingleton(Mock.Of()) + .AddSingleton(FileVersionProvider) .BuildServiceProvider(); var viewContext = new ViewContext diff --git a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/LinkTagHelperTest.cs b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/LinkTagHelperTest.cs index 309371a185..ddf6ed2834 100644 --- a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/LinkTagHelperTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/LinkTagHelperTest.cs @@ -55,8 +55,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { "href", hrefOutput }, }; var output = MakeTagHelperOutput("link", outputAttributes); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); var urlHelper = new Mock(); // Ensure expanded path does not look like an absolute path on Linux, avoiding @@ -69,17 +67,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers .Setup(f => f.GetUrlHelper(It.IsAny())) .Returns(urlHelper.Object); - var helper = new LinkTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - urlHelperFactory.Object) - { - ViewContext = viewContext, - AppendVersion = true, - Href = href, - }; + var helper = GetHelper(urlHelperFactory: urlHelperFactory.Object); + helper.AppendVersion = true; + helper.Href = href; // Act helper.Process(context, output); @@ -163,23 +153,14 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers new TagHelperAttribute("rel", new HtmlString("stylesheet")) })); var output = MakeTagHelperOutput("link", combinedOutputAttributes); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); - var helper = new LinkTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - ViewContext = viewContext, - FallbackHref = "test.css", - FallbackTestClass = "hidden", - FallbackTestProperty = "visibility", - FallbackTestValue = "hidden", - Href = "test.css", - }; + var helper = GetHelper(); + helper.FallbackHref = "test.css"; + helper.FallbackTestClass = "hidden"; + helper.FallbackTestProperty = "visibility"; + helper.FallbackTestValue = "hidden"; + helper.Href = "test.css"; + var expectedAttributes = new TagHelperAttributeList(output.Attributes); expectedAttributes.Add(new TagHelperAttribute("href", "test.css")); @@ -320,8 +301,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // Arrange var context = MakeTagHelperContext(attributes); var output = MakeTagHelperOutput("link"); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); var globbingUrlBuilder = new Mock( new TestFileProvider(), Mock.Of(), @@ -329,16 +308,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers globbingUrlBuilder.Setup(g => g.BuildUrlList(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new[] { "/common.css" }); - var helper = new LinkTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - ViewContext = viewContext, - GlobbingUrlBuilder = globbingUrlBuilder.Object - }; + var helper = GetHelper(); + helper.GlobbingUrlBuilder = globbingUrlBuilder.Object; + setProperties(helper); // Act @@ -417,8 +389,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // Arrange var context = MakeTagHelperContext(attributes); var output = MakeTagHelperOutput("link"); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); var globbingUrlBuilder = new Mock( new TestFileProvider(), Mock.Of(), @@ -426,16 +396,8 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers globbingUrlBuilder.Setup(g => g.BuildUrlList(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new[] { "/common.css" }); - var helper = new LinkTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - ViewContext = viewContext, - GlobbingUrlBuilder = globbingUrlBuilder.Object - }; + var helper = GetHelper(); + helper.GlobbingUrlBuilder = globbingUrlBuilder.Object; setProperties(helper); // Act @@ -469,23 +431,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { "rel", new HtmlString("stylesheet") }, { "data-extra", new HtmlString("something") }, }); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); - var helper = new LinkTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - ViewContext = viewContext, - FallbackHref = "test.css", - FallbackTestClass = "hidden", - FallbackTestProperty = "visibility", - FallbackTestValue = "hidden", - Href = "test.css", - }; + var helper = GetHelper(); + helper.FallbackHref = "test.css"; + helper.FallbackTestClass = "hidden"; + helper.FallbackTestProperty = "visibility"; + helper.FallbackTestValue = "hidden"; + helper.Href = "test.css"; // Act helper.Process(context, output); @@ -580,18 +532,8 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // Arrange var context = MakeTagHelperContext(attributes); var output = MakeTagHelperOutput("link"); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); - var helper = new LinkTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - ViewContext = viewContext, - }; + var helper = GetHelper(); setProperties(helper); // Act @@ -610,18 +552,8 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // Arrange var context = MakeTagHelperContext(); var output = MakeTagHelperOutput("link"); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); - var helper = new LinkTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - ViewContext = viewContext, - }; + var helper = GetHelper(); // Act helper.Process(context, output); @@ -650,8 +582,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { { "rel", new HtmlString("stylesheet") }, }); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); var globbingUrlBuilder = new Mock( new TestFileProvider(), Mock.Of(), @@ -659,18 +589,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers globbingUrlBuilder.Setup(g => g.BuildUrlList(null, "**/*.css", null)) .Returns(new[] { "/base.css" }); - var helper = new LinkTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - GlobbingUrlBuilder = globbingUrlBuilder.Object, - ViewContext = viewContext, - Href = "/css/site.css", - HrefInclude = "**/*.css", - }; + var helper = GetHelper(); + + helper.GlobbingUrlBuilder = globbingUrlBuilder.Object; + helper.Href = "/css/site.css"; + helper.HrefInclude = "**/*.css"; // Act helper.Process(context, output); @@ -713,8 +636,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { "literal", "all HTML encoded" }, { new TagHelperAttribute("mixed", mixed, HtmlAttributeValueStyle.SingleQuotes) }, }); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); var globbingUrlBuilder = new Mock( new TestFileProvider(), Mock.Of(), @@ -722,18 +643,10 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers globbingUrlBuilder.Setup(g => g.BuildUrlList(null, "**/*.css", null)) .Returns(new[] { "/base.css" }); - var helper = new LinkTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - GlobbingUrlBuilder = globbingUrlBuilder.Object, - Href = "/css/site.css", - HrefInclude = "**/*.css", - ViewContext = viewContext, - }; + var helper = GetHelper(); + helper.GlobbingUrlBuilder = globbingUrlBuilder.Object; + helper.Href = "/css/site.css"; + helper.HrefInclude = "**/*.css"; // Act helper.Process(context, output); @@ -760,20 +673,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { { "rel", new HtmlString("stylesheet") }, }); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); - var helper = new LinkTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - ViewContext = viewContext, - Href = "/css/site.css", - AppendVersion = true - }; + var helper = GetHelper(); + + helper.Href = "/css/site.css"; + helper.AppendVersion = true; // Act helper.Process(context, output); @@ -798,20 +702,12 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { { "rel", new HtmlString("stylesheet") }, }); - var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext("/bar"); - var helper = new LinkTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - ViewContext = viewContext, - Href = "/bar/css/site.css", - AppendVersion = true - }; + var helper = GetHelper(); + helper.ViewContext = viewContext; + helper.Href = "/bar/css/site.css"; + helper.AppendVersion = true; // Act helper.Process(context, output); @@ -850,8 +746,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { { "rel", new HtmlString("stylesheet") }, }); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); var globbingUrlBuilder = new Mock( new TestFileProvider(), Mock.Of(), @@ -859,22 +753,14 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers globbingUrlBuilder.Setup(g => g.BuildUrlList(null, "**/fallback.css", null)) .Returns(new[] { "/fallback.css" }); - var helper = new LinkTagHelper( - MakeHostingEnvironment(), - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - AppendVersion = true, - Href = "/css/site.css", - FallbackHrefInclude = "**/fallback.css", - FallbackTestClass = "hidden", - FallbackTestProperty = "visibility", - FallbackTestValue = "hidden", - GlobbingUrlBuilder = globbingUrlBuilder.Object, - ViewContext = viewContext, - }; + var helper = GetHelper(); + helper.AppendVersion = true; + helper.Href = "/css/site.css"; + helper.FallbackHrefInclude = "**/fallback.css"; + helper.FallbackTestClass = "hidden"; + helper.FallbackTestProperty = "visibility"; + helper.FallbackTestValue = "hidden"; + helper.GlobbingUrlBuilder = globbingUrlBuilder.Object; // Act helper.Process(context, output); @@ -929,8 +815,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { "mixed", mixed }, { "rel", new HtmlString("stylesheet") }, }); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); var globbingUrlBuilder = new Mock( new TestFileProvider(), Mock.Of(), @@ -938,22 +822,15 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers globbingUrlBuilder.Setup(g => g.BuildUrlList(null, "**/fallback.css", null)) .Returns(new[] { "/fallback.css" }); - var helper = new LinkTagHelper( - MakeHostingEnvironment(), - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - AppendVersion = true, - FallbackHrefInclude = "**/fallback.css", - FallbackTestClass = "hidden", - FallbackTestProperty = "visibility", - FallbackTestValue = "hidden", - GlobbingUrlBuilder = globbingUrlBuilder.Object, - Href = "/css/site.css", - ViewContext = viewContext, - }; + var helper = GetHelper(); + + helper.AppendVersion = true; + helper.FallbackHrefInclude = "**/fallback.css"; + helper.FallbackTestClass = "hidden"; + helper.FallbackTestProperty = "visibility"; + helper.FallbackTestValue = "hidden"; + helper.GlobbingUrlBuilder = globbingUrlBuilder.Object; + helper.Href = "/css/site.css"; // Act helper.Process(context, output); @@ -981,8 +858,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { { "rel", new HtmlString("stylesheet") }, }); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); var globbingUrlBuilder = new Mock( new TestFileProvider(), Mock.Of(), @@ -990,19 +865,12 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers globbingUrlBuilder.Setup(g => g.BuildUrlList(null, "**/*.css", null)) .Returns(new[] { "/base.css" }); - var helper = new LinkTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - GlobbingUrlBuilder = globbingUrlBuilder.Object, - ViewContext = viewContext, - Href = "/css/site.css", - HrefInclude = "**/*.css", - AppendVersion = true - }; + var helper = GetHelper(); + + helper.GlobbingUrlBuilder = globbingUrlBuilder.Object; + helper.Href = "/css/site.css"; + helper.HrefInclude = "**/*.css"; + helper.AppendVersion = true; // Act helper.Process(context, output); @@ -1016,12 +884,36 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers content); } + private static LinkTagHelper GetHelper( + IHostingEnvironment hostingEnvironment = null, + IUrlHelperFactory urlHelperFactory = null, + ViewContext viewContext = null) + { + hostingEnvironment = hostingEnvironment ?? MakeHostingEnvironment(); + urlHelperFactory = urlHelperFactory ?? MakeUrlHelperFactory(); + viewContext = viewContext ?? MakeViewContext(); + + var memoryCacheProvider = new TagHelperMemoryCacheProvider(); + var fileVersionProvider = new DefaultFileVersionProvider(hostingEnvironment, memoryCacheProvider); + + return new LinkTagHelper( + hostingEnvironment, + memoryCacheProvider, + fileVersionProvider, + new HtmlTestEncoder(), + new JavaScriptTestEncoder(), + urlHelperFactory) + { + ViewContext = viewContext, + }; + } + private static ViewContext MakeViewContext(string requestPathBase = null) { var actionContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()); if (requestPathBase != null) { - actionContext.HttpContext.Request.PathBase = new Http.PathString(requestPathBase); + actionContext.HttpContext.Request.PathBase = new PathString(requestPathBase); } var metadataProvider = new EmptyModelMetadataProvider(); diff --git a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs index eb6696292a..75f7da33a7 100644 --- a/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs @@ -56,8 +56,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { "src", srcOutput }, }; var output = MakeTagHelperOutput("script", outputAttributes); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); var urlHelper = new Mock(); // Ensure expanded path does not look like an absolute path on Linux, avoiding @@ -70,17 +68,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers .Setup(f => f.GetUrlHelper(It.IsAny())) .Returns(urlHelper.Object); - var helper = new ScriptTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - urlHelperFactory.Object) - { - ViewContext = viewContext, - AppendVersion = true, - Src = src, - }; + var helper = GetHelper(urlHelperFactory: urlHelperFactory.Object); + helper.AppendVersion = true; + helper.Src = src; // Act helper.Process(context, output); @@ -107,7 +97,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers new TagHelperAttribute("asp-fallback-test", "isavailable()"), })); var tagHelperContext = MakeTagHelperContext(allAttributes); - var viewContext = MakeViewContext(); var combinedOutputAttributes = new TagHelperAttributeList( outputAttributes.Concat( new[] @@ -115,20 +104,12 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers new TagHelperAttribute("data-extra", new HtmlString("something")) })); var output = MakeTagHelperOutput("script", combinedOutputAttributes); - var hostingEnvironment = MakeHostingEnvironment(); - var helper = new ScriptTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - ViewContext = viewContext, - FallbackSrc = "~/blank.js", - FallbackTestExpression = "http://www.example.com/blank.js", - Src = "/blank.js", - }; + var helper = GetHelper(); + helper.FallbackSrc = "~/blank.js"; + helper.FallbackTestExpression = "http://www.example.com/blank.js"; + helper.Src = "/blank.js"; + var expectedAttributes = new TagHelperAttributeList(output.Attributes); expectedAttributes.Add(new TagHelperAttribute("src", "/blank.js")); @@ -301,8 +282,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // Arrange var context = MakeTagHelperContext(attributes); var output = MakeTagHelperOutput("script"); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); var globbingUrlBuilder = new Mock( new TestFileProvider(), Mock.Of(), @@ -310,16 +289,8 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers globbingUrlBuilder.Setup(g => g.BuildUrlList(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new[] { "/common.js" }); - var helper = new ScriptTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - ViewContext = viewContext, - GlobbingUrlBuilder = globbingUrlBuilder.Object - }; + var helper = GetHelper(); + helper.GlobbingUrlBuilder = globbingUrlBuilder.Object; setProperties(helper); // Act @@ -398,8 +369,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers // Arrange var context = MakeTagHelperContext(attributes); var output = MakeTagHelperOutput("script"); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); var globbingUrlBuilder = new Mock( new TestFileProvider(), Mock.Of(), @@ -407,16 +376,8 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers globbingUrlBuilder.Setup(g => g.BuildUrlList(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new[] { "/common.js" }); - var helper = new ScriptTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - ViewContext = viewContext, - GlobbingUrlBuilder = globbingUrlBuilder.Object - }; + var helper = GetHelper(); + helper.GlobbingUrlBuilder = globbingUrlBuilder.Object; setProperties(helper); // Act @@ -503,18 +464,8 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelperContext = MakeTagHelperContext(attributes); var output = MakeTagHelperOutput("script"); var logger = new Mock>(); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); - var helper = new ScriptTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - ViewContext = viewContext, - }; + var helper = GetHelper(); setProperties(helper); // Act @@ -535,15 +486,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var viewContext = MakeViewContext(); var output = MakeTagHelperOutput("script"); - var helper = new ScriptTagHelper( - MakeHostingEnvironment(), - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - ViewContext = viewContext, - }; + var helper = GetHelper(); // Act helper.Process(tagHelperContext, output); @@ -569,8 +512,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers new TagHelperAttribute("asp-fallback-test", "isavailable()"), }); - var viewContext = MakeViewContext(); - var output = MakeTagHelperOutput("src", attributes: new TagHelperAttributeList { @@ -578,20 +519,10 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers new TagHelperAttribute("data-more", "else"), }); - var hostingEnvironment = MakeHostingEnvironment(); - - var helper = new ScriptTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - ViewContext = viewContext, - FallbackSrc = "~/blank.js", - FallbackTestExpression = "http://www.example.com/blank.js", - Src = "/blank.js", - }; + var helper = GetHelper(); + helper.FallbackSrc = "~/blank.js"; + helper.FallbackTestExpression = "http://www.example.com/blank.js"; + helper.Src = "/blank.js"; // Act helper.Process(tagHelperContext, output); @@ -615,8 +546,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers new TagHelperAttribute("asp-src-include", "**/*.js") }); var output = MakeTagHelperOutput("script", attributes: new TagHelperAttributeList()); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); var globbingUrlBuilder = new Mock( new TestFileProvider(), Mock.Of(), @@ -624,18 +553,10 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers globbingUrlBuilder.Setup(g => g.BuildUrlList(null, "**/*.js", null)) .Returns(new[] { "/common.js" }); - var helper = new ScriptTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - GlobbingUrlBuilder = globbingUrlBuilder.Object, - ViewContext = viewContext, - Src = "/js/site.js", - SrcInclude = "**/*.js", - }; + var helper = GetHelper(); + helper.GlobbingUrlBuilder = globbingUrlBuilder.Object; + helper.Src = "/js/site.js"; + helper.SrcInclude = "**/*.js"; // Act helper.Process(context, output); @@ -678,8 +599,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { "literal", "all HTML encoded"}, { new TagHelperAttribute("mixed", mixed, HtmlAttributeValueStyle.SingleQuotes) }, }); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); var globbingUrlBuilder = new Mock( new TestFileProvider(), Mock.Of(), @@ -687,18 +606,10 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers globbingUrlBuilder.Setup(g => g.BuildUrlList(null, "**/*.js", null)) .Returns(new[] { "/common.js" }); - var helper = new ScriptTagHelper( - hostingEnvironment, - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - GlobbingUrlBuilder = globbingUrlBuilder.Object, - Src = "/js/site.js", - SrcInclude = "**/*.js", - ViewContext = viewContext, - }; + var helper = GetHelper(); + helper.GlobbingUrlBuilder = globbingUrlBuilder.Object; + helper.Src = "/js/site.js"; + helper.SrcInclude = "**/*.js"; // Act helper.Process(context, output); @@ -722,20 +633,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers }); var output = MakeTagHelperOutput("script", attributes: new TagHelperAttributeList()); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); - - var helper = new ScriptTagHelper( - MakeHostingEnvironment(), - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - ViewContext = viewContext, - AppendVersion = true, - Src = "/js/site.js", - }; + var helper = GetHelper(); + helper.Src = "/js/site.js"; + helper.AppendVersion = true; // Act helper.Process(context, output); @@ -756,20 +656,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers new TagHelperAttribute("asp-append-version", "true") }); var output = MakeTagHelperOutput("script", attributes: new TagHelperAttributeList()); - var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext("/bar"); - var helper = new ScriptTagHelper( - MakeHostingEnvironment(), - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - ViewContext = viewContext, - AppendVersion = true, - Src = "/bar/js/site.js", - }; + var helper = GetHelper(viewContext: viewContext); + helper.Src = "/bar/js/site.js"; + helper.AppendVersion = true; // Act helper.Process(context, output); @@ -792,22 +683,12 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers new TagHelperAttribute("asp-append-version", "true") }); var output = MakeTagHelperOutput("script", attributes: new TagHelperAttributeList()); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); - var helper = new ScriptTagHelper( - MakeHostingEnvironment(), - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - ViewContext = viewContext, - FallbackSrc = "fallback.js", - FallbackTestExpression = "isavailable()", - AppendVersion = true, - Src = "/js/site.js", - }; + var helper = GetHelper(); + helper.FallbackSrc = "fallback.js"; + helper.FallbackTestExpression = "isavailable()"; + helper.AppendVersion = true; + helper.Src = "/js/site.js"; // Act helper.Process(context, output); @@ -855,22 +736,12 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers { "literal", "all HTML encoded" }, { new TagHelperAttribute("mixed", mixed, HtmlAttributeValueStyle.SingleQuotes) }, }); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); - var helper = new ScriptTagHelper( - MakeHostingEnvironment(), - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - AppendVersion = true, - FallbackSrc = "fallback.js", - FallbackTestExpression = "isavailable()", - Src = "/js/site.js", - ViewContext = viewContext, - }; + var helper = GetHelper(); + helper.AppendVersion = true; + helper.FallbackSrc = "fallback.js"; + helper.FallbackTestExpression = "isavailable()"; + helper.Src = "/js/site.js"; // Act helper.Process(context, output); @@ -897,8 +768,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers new TagHelperAttribute("asp-append-version", "true") }); var output = MakeTagHelperOutput("script", attributes: new TagHelperAttributeList()); - var hostingEnvironment = MakeHostingEnvironment(); - var viewContext = MakeViewContext(); var globbingUrlBuilder = new Mock( new TestFileProvider(), Mock.Of(), @@ -906,19 +775,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers globbingUrlBuilder.Setup(g => g.BuildUrlList(null, "*.js", null)) .Returns(new[] { "/common.js" }); - var helper = new ScriptTagHelper( - MakeHostingEnvironment(), - new TagHelperMemoryCacheProvider(), - new HtmlTestEncoder(), - new JavaScriptTestEncoder(), - MakeUrlHelperFactory()) - { - GlobbingUrlBuilder = globbingUrlBuilder.Object, - ViewContext = viewContext, - SrcInclude = "*.js", - AppendVersion = true, - Src = "/js/site.js", - }; + var helper = GetHelper(); + helper.GlobbingUrlBuilder = globbingUrlBuilder.Object; + helper.SrcInclude = "*.js"; + helper.AppendVersion = true; + helper.Src = "/js/site.js"; // Act helper.Process(context, output); @@ -930,6 +791,30 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers Assert.Equal(expectedContent, content); } + private static ScriptTagHelper GetHelper( + IHostingEnvironment hostingEnvironment = null, + IUrlHelperFactory urlHelperFactory = null, + ViewContext viewContext = null) + { + hostingEnvironment = hostingEnvironment ?? MakeHostingEnvironment(); + urlHelperFactory = urlHelperFactory ?? MakeUrlHelperFactory(); + viewContext = viewContext ?? MakeViewContext(); + + var memoryCacheProvider = new TagHelperMemoryCacheProvider(); + var fileVersionProvider = new DefaultFileVersionProvider(hostingEnvironment, memoryCacheProvider); + + return new ScriptTagHelper( + hostingEnvironment, + memoryCacheProvider, + fileVersionProvider, + new HtmlTestEncoder(), + new JavaScriptTestEncoder(), + urlHelperFactory) + { + ViewContext = viewContext, + }; + } + private TagHelperContext MakeTagHelperContext( TagHelperAttributeList attributes = null, string content = null)