diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/GlobbingUrlBuilder.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/GlobbingUrlBuilder.cs index d3fc0f8091..5deb316f21 100644 --- a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/GlobbingUrlBuilder.cs +++ b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/GlobbingUrlBuilder.cs @@ -3,11 +3,12 @@ using System; using System.Collections.Generic; -using System.Linq; using Microsoft.AspNet.FileProviders; using Microsoft.AspNet.Http; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.FileSystemGlobbing; +using Microsoft.Extensions.Internal; +using Microsoft.Extensions.Primitives; namespace Microsoft.AspNet.Mvc.TagHelpers.Internal { @@ -17,18 +18,19 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal /// public class GlobbingUrlBuilder { - private static readonly char[] PatternSeparator = new[] { ',' }; + private static readonly IReadOnlyList EmptyList = +#if NET451 + new string[0]; +#else + Array.Empty(); +#endif // Valid whitespace characters defined by the HTML5 spec. private static readonly char[] ValidAttributeWhitespaceChars = new[] { '\t', '\n', '\u000C', '\r', ' ' }; - private static readonly PathComparer DefaultPathComparer = new PathComparer(); - private readonly FileProviderGlobbingDirectory _baseGlobbingDirectory; - public GlobbingUrlBuilder() { } - /// /// Creates a new . /// @@ -42,6 +44,11 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal throw new ArgumentNullException(nameof(fileProvider)); } + if (cache == null) + { + throw new ArgumentNullException(nameof(cache)); + } + FileProvider = fileProvider; Cache = cache; RequestPathBase = requestPathBase; @@ -73,93 +80,103 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal /// The file globbing include pattern. /// The file globbing exclude pattern. /// The list of URLs - public virtual ICollection BuildUrlList(string staticUrl, string includePattern, string excludePattern) + public virtual IReadOnlyList BuildUrlList( + string staticUrl, + string includePattern, + string excludePattern) { - var urls = new HashSet(StringComparer.Ordinal); + // Get urls that match the globbing patterns specified + var globbedUrls = ExpandGlobbedUrl(includePattern, excludePattern); - // Add the statically declared url if present - if (staticUrl != null) + if (staticUrl == null) { - urls.Add(staticUrl); + return globbedUrls; } - // Add urls that match the globbing patterns specified - var matchedUrls = ExpandGlobbedUrl(includePattern, excludePattern); - urls.UnionWith(matchedUrls); + // The staticUrl always appears first in the sequence. + var urls = new List(1 + globbedUrls.Count) + { + staticUrl + }; + + for (var i = 0; i < globbedUrls.Count; i++) + { + if (!string.Equals(staticUrl, globbedUrls[i], StringComparison.Ordinal)) + { + urls.Add(globbedUrls[i]); + } + } return urls; } - private IEnumerable ExpandGlobbedUrl(string include, string exclude) + private IReadOnlyList ExpandGlobbedUrl(string include, string exclude) { if (string.IsNullOrEmpty(include)) { - return Enumerable.Empty(); + return EmptyList; } - var includePatterns = include.Split(PatternSeparator, StringSplitOptions.RemoveEmptyEntries); - var excludePatterns = exclude?.Split(PatternSeparator, StringSplitOptions.RemoveEmptyEntries); - - if (includePatterns.Length == 0) + var cacheKey = new GlobbingUrlKey(include, exclude); + List files; + if (Cache.TryGetValue(cacheKey, out files)) { - return Enumerable.Empty(); - } - - if (Cache != null) - { - var cacheKey = $"{nameof(GlobbingUrlBuilder)}-inc:{include}-exc:{exclude}"; - IEnumerable files; - if (!Cache.TryGetValue(cacheKey, out files)) - { - var options = new MemoryCacheEntryOptions(); - - for (var i = 0; i < includePatterns.Length; i++) - { - var changeToken = FileProvider.Watch(includePatterns[i]); - options.AddExpirationToken(changeToken); - } - - files = FindFiles(includePatterns, excludePatterns); - - Cache.Set(cacheKey, files, options); - } return files; } - return FindFiles(includePatterns, excludePatterns); - } - - private IEnumerable FindFiles(string[] includePatterns, string[] excludePatterns) - { - var matcher = MatcherBuilder != null ? MatcherBuilder() : new Matcher(); - var trimmedIncludePatterns = new List(); - for (var i = 0; i < includePatterns.Length; i++) + var includeTokenizer = new StringTokenizer(include, ','); + var includeEnumerator = includeTokenizer.GetEnumerator(); + if (!includeEnumerator.MoveNext()) { - trimmedIncludePatterns.Add(TrimLeadingTildeSlash(includePatterns[i])); + return EmptyList; } + + var options = new MemoryCacheEntryOptions(); + var trimmedIncludePatterns = new List(); + foreach (var includePattern in includeTokenizer) + { + var changeToken = FileProvider.Watch(includePattern.Value); + options.AddExpirationToken(changeToken); + trimmedIncludePatterns.Add(NormalizePath(includePattern)); + } + var matcher = MatcherBuilder != null ? MatcherBuilder() : new Matcher(); matcher.AddIncludePatterns(trimmedIncludePatterns); - if (excludePatterns != null) + if (!string.IsNullOrWhiteSpace(exclude)) { + var excludeTokenizer = new StringTokenizer(exclude, ','); var trimmedExcludePatterns = new List(); - for (var i = 0; i < excludePatterns.Length; i++) + foreach (var excludePattern in excludeTokenizer) { - trimmedExcludePatterns.Add(TrimLeadingTildeSlash(excludePatterns[i])); + trimmedExcludePatterns.Add(NormalizePath(excludePattern)); } matcher.AddExcludePatterns(trimmedExcludePatterns); } - var matches = matcher.Execute(_baseGlobbingDirectory); - - return matches.Files.Select(ResolveMatchedPath) - .OrderBy(path => path, DefaultPathComparer); + return Cache.Set>( + cacheKey, + FindFiles(matcher), + options); } - private string ResolveMatchedPath(FilePatternMatch matchedPath) + private List FindFiles(Matcher matcher) { - // Resolve the path to site root - var relativePath = new PathString("/" + matchedPath.Path); - return RequestPathBase.Add(relativePath).ToString(); + var matches = matcher.Execute(_baseGlobbingDirectory); + var matchedUrls = new List(); + foreach (var matchedPath in matches.Files) + { + // Resolve the path to site root + var relativePath = new PathString("/" + matchedPath.Path); + var matchedUrl = RequestPathBase.Add(relativePath).ToString(); + var index = matchedUrls.BinarySearch(matchedUrl, DefaultPathComparer); + if (index < 0) + { + // Item doesn't already exist. Insert it. + matchedUrls.Insert(~index, matchedUrl); + } + } + + return matchedUrls; } private class PathComparer : IComparer @@ -189,60 +206,180 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal yExtIndex = yExtIndex > ySlashIndex ? yExtIndex : -1; // Get paths without their extensions, if they have one + var xLength = xExtIndex >= 0 ? xExtIndex : x.Length; + var yLength = yExtIndex >= 0 ? yExtIndex : y.Length; + var compareLength = Math.Max(xLength, yLength); + + // In the resulting sequence, we want shorter paths to appear prior to longer paths. For paths of equal + // depth, we'll compare individual segments. The first segment that differs determines the result. + // For e.g. + // Foo.cshtml < Foo.xhtml + // Bar.cshtml < Foo.cshtml + // ZZ/z.txt < A/A/a.txt + // ZZ/a/z.txt < ZZ/z/a.txt + + if (string.Compare(x, 0, y, 0, compareLength, StringComparison.Ordinal) == 0) + { + // Only extension differs so just compare the extension + if (xExtIndex >= 0 && yExtIndex >= 0) + { + var length = x.Length - xExtIndex; + return string.Compare(x, xExtIndex, y, yExtIndex, length, StringComparison.Ordinal); + } + + return xExtIndex - yExtIndex; + } + var xNoExt = xExtIndex >= 0 ? x.Substring(0, xExtIndex) : x; var yNoExt = yExtIndex >= 0 ? y.Substring(0, yExtIndex) : y; - if (string.Equals(xNoExt, yNoExt, StringComparison.Ordinal)) + var result = 0; + var xEnumerator = new StringTokenizer(xNoExt, '/').GetEnumerator(); + var yEnumerator = new StringTokenizer(yNoExt, '/').GetEnumerator(); + StringSegment xSegment; + StringSegment ySegment; + while (TryGetNextSegment(ref xEnumerator, out xSegment)) { - // Only extension differs so just compare the extension - var xExt = xExtIndex >= 0 ? x.Substring(xExtIndex) : string.Empty; - var yExt = yExtIndex >= 0 ? y.Substring(yExtIndex) : string.Empty; - return string.Compare(xExt, yExt, StringComparison.Ordinal); - } - - var xSegments = xNoExt.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - var ySegments = yNoExt.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - - if (xSegments.Length != ySegments.Length) - { - // Different path depths so shallower path wins - return xSegments.Length.CompareTo(ySegments.Length); - } - - // Depth is the same so compare each segment - for (int i = 0; i < xSegments.Length; i++) - { - var xSegment = xSegments[i]; - var ySegment = ySegments[i]; - - var xToY = string.Compare(xSegment, ySegment, StringComparison.Ordinal); - if (xToY != 0) + if (!TryGetNextSegment(ref yEnumerator, out ySegment)) { - return xToY; + // Different path depths (right is shorter), so shallower path wins. + return 1; + } + + if (result != 0) + { + // Once we've determined that a segment differs, we need to ensure that the two paths + // are of equal depth. + continue; + } + + var length = Math.Max(xSegment.Length, ySegment.Length); + result = string.Compare( + xSegment.Buffer, + xSegment.Offset, + ySegment.Buffer, + ySegment.Offset, + length, + StringComparison.Ordinal); + } + + if (TryGetNextSegment(ref yEnumerator, out ySegment)) + { + // Different path depths (left is shorter). Shallower path wins. + return -1; + } + else + { + // Segments are of equal length + return result; + } + } + + private static bool TryGetNextSegment(ref StringTokenizer.Enumerator enumerator, out StringSegment segment) + { + while (enumerator.MoveNext()) + { + if (enumerator.Current.HasValue && enumerator.Current.Length > 0) + { + segment = enumerator.Current; + return true; } } - // Should't get here, but if we do, hey, they're the same :) - return 0; + segment = default(StringSegment); + return false; } } - private static string TrimLeadingTildeSlash(string value) + private static string NormalizePath(StringSegment value) { - var result = value.Trim(ValidAttributeWhitespaceChars); - - if (result.StartsWith("~/", StringComparison.Ordinal)) + if (!value.HasValue || value.Length == 0) { - result = result.Substring(2); + return null; } - else if (result.StartsWith("/", StringComparison.Ordinal) || - result.StartsWith("\\", StringComparison.Ordinal)) + + value = Trim(value); + if (value.StartsWith("~/", StringComparison.Ordinal)) + { + value = new StringSegment(value.Buffer, value.Offset + 2, value.Length - 2); + } + else if (value.StartsWith("/", StringComparison.Ordinal) || + value.StartsWith("\\", StringComparison.Ordinal)) { // Trim the leading slash as the matcher runs from the provided root only anyway - result = result.Substring(1); + value = new StringSegment(value.Buffer, value.Offset + 1, value.Length - 1); } - return result; + return value.Value; + } + + private static bool IsWhiteSpace(string value, int index) + { + for (var i = 0; i < ValidAttributeWhitespaceChars.Length; i++) + { + if (value[index] == ValidAttributeWhitespaceChars[i]) + { + return true; + } + } + + return false; + } + + private static StringSegment Trim(StringSegment value) + { + var offset = value.Offset; + while (offset < value.Offset + value.Length) + { + if (!IsWhiteSpace(value.Buffer, offset)) + { + break; + } + + offset++; + } + + var trimmedEnd = value.Offset + value.Length - 1; + while (trimmedEnd >= offset) + { + if (!IsWhiteSpace(value.Buffer, trimmedEnd)) + { + break; + } + + trimmedEnd--; + } + + return new StringSegment(value.Buffer, offset, trimmedEnd - offset + 1); + } + + private struct GlobbingUrlKey : IEquatable + { + public GlobbingUrlKey(string include, string exclude) + { + Include = include; + Exclude = exclude; + } + + public string Include { get; } + + public string Exclude { get; } + + public bool Equals(GlobbingUrlKey other) + { + return string.Equals(Include, other.Include, StringComparison.Ordinal) && + string.Equals(Exclude, other.Exclude, StringComparison.Ordinal); + + } + + public override int GetHashCode() + { + var hashCodeCombiner = HashCodeCombiner.Start(); + hashCodeCombiner.Add(Include); + hashCodeCombiner.Add(Exclude); + + return hashCodeCombiner.CombinedHash; + } } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/JavaScriptStringArrayEncoder.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/JavaScriptStringArrayEncoder.cs deleted file mode 100644 index 983d1c83ed..0000000000 --- a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/JavaScriptStringArrayEncoder.cs +++ /dev/null @@ -1,43 +0,0 @@ -// 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.IO; -using System.Text.Encodings.Web; - -namespace Microsoft.AspNet.Mvc.TagHelpers.Internal -{ - /// - /// Methods for encoding string[]s for use as a JavaScript array literal. - /// - public static class JavaScriptStringArrayEncoder - { - /// - /// Encodes a string[] for safe use as a JavaScript array literal in many contexts, including - /// inline in an HTML file. - /// - public static string Encode(JavaScriptEncoder encoder, string[] values) - { - var writer = new StringWriter(); - writer.Write('['); - - // Perf: Avoid allocating enumerator - var firstAdded = false; - for (var i = 0; i < values.Length; i++) - { - if (firstAdded) - { - writer.Write(','); - } - - writer.Write('"'); - encoder.Encode(writer, values[i]); - writer.Write('"'); - firstAdded = true; - } - - writer.Write(']'); - - return writer.ToString(); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/LinkTagHelper.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/LinkTagHelper.cs index 89afb93467..7ee10eb99d 100644 --- a/src/Microsoft.AspNet.Mvc.TagHelpers/LinkTagHelper.cs +++ b/src/Microsoft.AspNet.Mvc.TagHelpers/LinkTagHelper.cs @@ -2,14 +2,16 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Diagnostics; -using System.Linq; +using System.Text; using System.Text.Encodings.Web; using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Mvc.Razor.TagHelpers; using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.TagHelpers.Internal; +using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Razor.TagHelpers; using Microsoft.Extensions.Caching.Memory; @@ -288,8 +290,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers // Build a tag for each matched href. var urls = GlobbingUrlBuilder.BuildUrlList(null, HrefInclude, HrefExclude); - foreach (var url in urls) + for (var i = 0; i < urls.Count; i++) { + var url = urls[i]; + // "url" values come from bound attributes and globbing. Must always be non-null. Debug.Assert(url != null); @@ -307,45 +311,70 @@ namespace Microsoft.AspNet.Mvc.TagHelpers private void BuildFallbackBlock(TagHelperContent builder) { EnsureGlobbingUrlBuilder(); - var fallbackHrefs = - GlobbingUrlBuilder.BuildUrlList(FallbackHref, FallbackHrefInclude, FallbackHrefExclude).ToArray(); + var fallbackHrefs = GlobbingUrlBuilder.BuildUrlList( + FallbackHref, + FallbackHrefInclude, + FallbackHrefExclude); - if (fallbackHrefs.Length > 0) + if (fallbackHrefs.Count == 0) { - if (AppendVersion == true) - { - for (var i = 0; i < fallbackHrefs.Length; i++) - { - // fallbackHrefs come from bound attributes and globbing. Must always be non-null. - Debug.Assert(fallbackHrefs[i] != null); + return; + } - fallbackHrefs[i] = _fileVersionProvider.AddFileVersionToPath(fallbackHrefs[i]); - } + builder.AppendHtml(HtmlString.NewLine); + + // Build the tag that's used to test for the presence of the stylesheet + builder + .AppendHtml(""); + + // Build the "); + } + + private void AppendFallbackHrefs(TagHelperContent builder, IReadOnlyList fallbackHrefs) + { + builder.AppendHtml("["); + var firstAdded = false; + // Perf: Avoid allocating enumerator + for (var i = 0; i < fallbackHrefs.Count; i++) + { + if (firstAdded) + { + builder.AppendHtml(",\""); + } + else + { + builder.AppendHtml("\""); + firstAdded = true; } - builder.AppendHtml(HtmlString.NewLine); + // fallbackHrefs come from bound attributes and globbing. Must always be non-null. + Debug.Assert(fallbackHrefs[i] != null); + var valueToWrite = fallbackHrefs[i]; + if (AppendVersion == true) + { + valueToWrite = _fileVersionProvider.AddFileVersionToPath(fallbackHrefs[i]); + } - // Build the tag that's used to test for the presence of the stylesheet - builder - .AppendHtml(""); - - // Build the "); + builder.AppendHtml(JavaScriptEncoder.Encode(valueToWrite)); + builder.AppendHtml("\""); } + builder.AppendHtml("]);"); } private void EnsureGlobbingUrlBuilder() diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/project.json b/src/Microsoft.AspNet.Mvc.TagHelpers/project.json index 5fd05809dc..4494ed4512 100644 --- a/src/Microsoft.AspNet.Mvc.TagHelpers/project.json +++ b/src/Microsoft.AspNet.Mvc.TagHelpers/project.json @@ -21,6 +21,10 @@ "Microsoft.Extensions.PropertyHelper.Sources": { "version": "1.0.0-*", "type": "build" + }, + "Microsoft.Extensions.HashCodeCombiner.Sources": { + "version": "1.0.0-*", + "type": "build" } }, "frameworks": { diff --git a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/Internal/GlobbingUrlBuilderTest.cs b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/Internal/GlobbingUrlBuilderTest.cs index 860402c546..3bf3bd9f03 100644 --- a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/Internal/GlobbingUrlBuilderTest.cs +++ b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/Internal/GlobbingUrlBuilderTest.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal { // Arrange var fileProvider = MakeFileProvider(); - IMemoryCache cache = null; + var cache = new MemoryCache(new MemoryCacheOptions()); var requestPathBase = PathString.Empty; var globbingUrlBuilder = new GlobbingUrlBuilder(fileProvider, cache, requestPathBase); @@ -38,7 +38,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal { // Arrange var fileProvider = MakeFileProvider(MakeDirectoryContents("site.css", "blank.css")); - IMemoryCache cache = null; + var cache = new MemoryCache(new MemoryCacheOptions()); var requestPathBase = PathString.Empty; var globbingUrlBuilder = new GlobbingUrlBuilder(fileProvider, cache, requestPathBase); @@ -210,7 +210,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal { // Arrange var fileProvider = MakeFileProvider(dirStructure); - IMemoryCache cache = null; + var cache = new MemoryCache(new MemoryCacheOptions()); var requestPathBase = PathString.Empty; var globbingUrlBuilder = new GlobbingUrlBuilder(fileProvider, cache, requestPathBase); @@ -230,7 +230,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal { // Arrange var fileProvider = MakeFileProvider(MakeDirectoryContents("site.css", "blank.css")); - IMemoryCache cache = null; + var cache = new MemoryCache(new MemoryCacheOptions()); var requestPathBase = new PathString(pathBase); var globbingUrlBuilder = new GlobbingUrlBuilder(fileProvider, cache, requestPathBase); @@ -277,10 +277,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal Mock.Get(fileProvider).Setup(f => f.Watch(It.IsAny())).Returns(changeToken.Object); var cache = MakeCache(); Mock.Get(cache).Setup(c => c.Set( - /*key*/ It.IsAny(), - /*value*/ It.IsAny(), + /*key*/ It.IsAny(), + /*value*/ It.IsAny>(), /*options*/ It.IsAny())) - .Returns(new object()) + .Returns((object key, object value, MemoryCacheEntryOptions options) => value) .Verifiable(); var requestPathBase = PathString.Empty; var globbingUrlBuilder = new GlobbingUrlBuilder(fileProvider, cache, requestPathBase); @@ -339,7 +339,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal { // Arrange var fileProvider = MakeFileProvider(MakeDirectoryContents("site.css", "blank.js", "site2.txt", "site.js")); - IMemoryCache cache = null; + var cache = new MemoryCache(new MemoryCacheOptions()); var requestPathBase = PathString.Empty; var globbingUrlBuilder = new GlobbingUrlBuilder(fileProvider, cache, requestPathBase); @@ -363,7 +363,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal { // Arrange var fileProvider = MakeFileProvider(MakeDirectoryContents("site.css", "blank.css")); - IMemoryCache cache = null; + var cache = new MemoryCache(new MemoryCacheOptions()); var requestPathBase = PathString.Empty; var includePatterns = new List(); var excludePatterns = new List(); @@ -391,7 +391,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal // Arrange var leadingSlashes = $"{prefix}{prefix}"; var fileProvider = MakeFileProvider(MakeDirectoryContents("site.css", "blank.css")); - IMemoryCache cache = null; + var cache = new MemoryCache(new MemoryCacheOptions()); var requestPathBase = PathString.Empty; var includePatterns = new List(); var excludePatterns = new List(); @@ -448,6 +448,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal var fileProvider = new Mock(MockBehavior.Strict); fileProvider.Setup(fp => fp.GetDirectoryContents(string.Empty)) .Returns(MakeDirectoryContents(rootNode, fileProvider)); + fileProvider.Setup(fp => fp.Watch(It.IsAny())) + .Returns(new TestFileChangeToken()); return fileProvider.Object; } @@ -494,13 +496,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal var fileProvider = new Mock(); fileProvider.Setup(fp => fp.GetDirectoryContents(It.IsAny())) .Returns(directoryContents); + fileProvider.Setup(fp => fp.Watch(It.IsAny())) + .Returns(new TestFileChangeToken()); return fileProvider.Object; } private static IMemoryCache MakeCache(object result = null) { var cache = new Mock(); - cache.Setup(c => c.TryGetValue(It.IsAny(), out result)) + cache.Setup(c => c.TryGetValue(It.IsAny(), out result)) .Returns(result != null); return cache.Object; } diff --git a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/LinkTagHelperTest.cs b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/LinkTagHelperTest.cs index a15acf2a17..aadd202804 100644 --- a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/LinkTagHelperTest.cs +++ b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/LinkTagHelperTest.cs @@ -9,9 +9,11 @@ using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.FileProviders; using Microsoft.AspNet.Hosting; +using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Mvc.Abstractions; using Microsoft.AspNet.Mvc.ModelBinding; +using Microsoft.AspNet.Mvc.Razor; using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.TagHelpers.Internal; @@ -279,7 +281,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers var output = MakeTagHelperOutput("link"); var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); - var globbingUrlBuilder = new Mock(); + var globbingUrlBuilder = new Mock( + new TestFileProvider(), + Mock.Of(), + PathString.Empty); globbingUrlBuilder.Setup(g => g.BuildUrlList(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new[] { "/common.css" }); @@ -373,7 +378,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers var output = MakeTagHelperOutput("link"); var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); - var globbingUrlBuilder = new Mock(); + var globbingUrlBuilder = new Mock( + new TestFileProvider(), + Mock.Of(), + PathString.Empty); globbingUrlBuilder.Setup(g => g.BuildUrlList(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new[] { "/common.css" }); @@ -597,7 +605,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers }); var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); - var globbingUrlBuilder = new Mock(); + var globbingUrlBuilder = new Mock( + new TestFileProvider(), + Mock.Of(), + PathString.Empty); globbingUrlBuilder.Setup(g => g.BuildUrlList(null, "**/*.css", null)) .Returns(new[] { "/base.css" }); @@ -640,7 +651,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers }); var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); - var globbingUrlBuilder = new Mock(); + var globbingUrlBuilder = new Mock( + new TestFileProvider(), + Mock.Of(), + PathString.Empty); globbingUrlBuilder.Setup(g => g.BuildUrlList(null, "**/*.css", null)) .Returns(new[] { "/base.css" }); @@ -761,7 +775,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers }); var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); - var globbingUrlBuilder = new Mock(); + var globbingUrlBuilder = new Mock( + new TestFileProvider(), + Mock.Of(), + PathString.Empty); globbingUrlBuilder.Setup(g => g.BuildUrlList(null, "**/*.css", null)) .Returns(new[] { "/base.css" }); diff --git a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs index 02dd340154..0ed12ed685 100644 --- a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs +++ b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs @@ -9,9 +9,11 @@ using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.FileProviders; using Microsoft.AspNet.Hosting; +using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Mvc.Abstractions; using Microsoft.AspNet.Mvc.ModelBinding; +using Microsoft.AspNet.Mvc.Razor; using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.TagHelpers.Internal; @@ -272,7 +274,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers var output = MakeTagHelperOutput("script"); var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); - var globbingUrlBuilder = new Mock(); + var globbingUrlBuilder = new Mock( + new TestFileProvider(), + Mock.Of(), + PathString.Empty); globbingUrlBuilder.Setup(g => g.BuildUrlList(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new[] { "/common.js" }); @@ -366,7 +371,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers var output = MakeTagHelperOutput("script"); var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); - var globbingUrlBuilder = new Mock(); + var globbingUrlBuilder = new Mock( + new TestFileProvider(), + Mock.Of(), + PathString.Empty); globbingUrlBuilder.Setup(g => g.BuildUrlList(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(new[] { "/common.js" }); @@ -573,7 +581,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers var output = MakeTagHelperOutput("script", attributes: new TagHelperAttributeList()); var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); - var globbingUrlBuilder = new Mock(); + var globbingUrlBuilder = new Mock( + new TestFileProvider(), + Mock.Of(), + PathString.Empty); globbingUrlBuilder.Setup(g => g.BuildUrlList(null, "**/*.js", null)) .Returns(new[] { "/common.js" }); @@ -612,7 +623,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers var output = MakeTagHelperOutput("script", attributes: new TagHelperAttributeList()); var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); - var globbingUrlBuilder = new Mock(); + var globbingUrlBuilder = new Mock( + new TestFileProvider(), + Mock.Of(), + PathString.Empty); globbingUrlBuilder.Setup(g => g.BuildUrlList(null, "**/*.js", null)) .Returns(new[] { "/common.js" }); @@ -762,7 +776,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers var output = MakeTagHelperOutput("script", attributes: new TagHelperAttributeList()); var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); - var globbingUrlBuilder = new Mock(); + var globbingUrlBuilder = new Mock( + new TestFileProvider(), + Mock.Of(), + PathString.Empty); globbingUrlBuilder.Setup(g => g.BuildUrlList(null, "*.js", null)) .Returns(new[] { "/common.js" });