diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/AttributeMatcher.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/AttributeMatcher.cs
index 2d88203dcb..03174ad580 100644
--- a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/AttributeMatcher.cs
+++ b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/AttributeMatcher.cs
@@ -13,16 +13,20 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
public static class AttributeMatcher
{
///
- /// Determines the modes a can run in based on which modes have all their required
- /// attributes present, non null, non empty, and non whitepsace.
+ /// Determines the most effective mode a can run in based on which modes have
+ /// all their required attributes present.
///
/// The type representing the 's modes.
/// The .
/// The modes and their required attributes.
- /// The .
- public static ModeMatchResult DetermineMode(
+ /// A comparer delegate.
+ /// The resulting most effective mode.
+ /// true if a mode was determined, otherwise false.
+ public static bool TryDetermineMode(
TagHelperContext context,
- IReadOnlyList> modeInfos)
+ IReadOnlyList> modeInfos,
+ Func compare,
+ out TMode result)
{
if (context == null)
{
@@ -34,100 +38,57 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
throw new ArgumentNullException(nameof(modeInfos));
}
- // true == full match, false == partial match
- var matchedAttributes = new Dictionary(StringComparer.OrdinalIgnoreCase);
- var result = new ModeMatchResult();
+ if (compare == null)
+ {
+ throw new ArgumentNullException(nameof(compare));
+ }
+
+ var foundResult = false;
+ result = default(TMode);
// Perf: Avoid allocating enumerator
for (var i = 0; i < modeInfos.Count; i++)
{
var modeInfo = modeInfos[i];
- var modeAttributes = GetPresentMissingAttributes(context, modeInfo.Attributes);
-
- if (modeAttributes.Present.Count > 0)
+ if (!HasMissingAttributes(context, modeInfo.Attributes) &&
+ compare(result, modeInfo.Mode) <= 0)
{
- if (modeAttributes.Missing.Count == 0)
- {
- // Perf: Avoid allocating enumerator
- // A complete match, mark the attribute as fully matched
- for (var j = 0; j < modeAttributes.Present.Count; j++)
- {
- matchedAttributes[modeAttributes.Present[j]] = true;
- }
-
- result.FullMatches.Add(ModeMatchAttributes.Create(modeInfo.Mode, modeInfo.Attributes));
- }
- else
- {
- // Perf: Avoid allocating enumerator
- // A partial match, mark the attribute as partially matched if not already fully matched
- for (var j = 0; j < modeAttributes.Present.Count; j++)
- {
- var attribute = modeAttributes.Present[j];
- bool attributeMatch;
- if (!matchedAttributes.TryGetValue(attribute, out attributeMatch))
- {
- matchedAttributes[attribute] = false;
- }
- }
-
- result.PartialMatches.Add(ModeMatchAttributes.Create(
- modeInfo.Mode, modeAttributes.Present, modeAttributes.Missing));
- }
+ foundResult = true;
+ result = modeInfo.Mode;
}
}
- // Build the list of partially matched attributes (those with partial matches but no full matches)
- foreach (var attribute in matchedAttributes.Keys)
- {
- if (!matchedAttributes[attribute])
- {
- result.PartiallyMatchedAttributes.Add(attribute);
- }
- }
-
- return result;
+ return foundResult;
}
- private static PresentMissingAttributes GetPresentMissingAttributes(
- TagHelperContext context,
- string[] requiredAttributes)
+ private static bool HasMissingAttributes(TagHelperContext context, string[] requiredAttributes)
{
- // Check for all attribute values
- var presentAttributes = new List();
- var missingAttributes = new List();
+ if (context.AllAttributes.Count < requiredAttributes.Length)
+ {
+ // If there are fewer attributes present than required, one or more of them must be missing.
+ return true;
+ }
+ // Check for all attribute values
// Perf: Avoid allocating enumerator
for (var i = 0; i < requiredAttributes.Length; i++)
{
- var requiredAttribute = requiredAttributes[i];
IReadOnlyTagHelperAttribute attribute;
- if (!context.AllAttributes.TryGetAttribute(requiredAttribute, out attribute))
+ if (!context.AllAttributes.TryGetAttribute(requiredAttributes[i], out attribute))
{
// Missing attribute.
- missingAttributes.Add(requiredAttribute);
- continue;
+ return true;
}
var valueAsString = attribute.Value as string;
if (valueAsString != null && string.IsNullOrEmpty(valueAsString))
{
// Treat attributes with empty values as missing.
- missingAttributes.Add(requiredAttribute);
- continue;
+ return true;
}
-
- presentAttributes.Add(requiredAttribute);
}
- return new PresentMissingAttributes { Present = presentAttributes, Missing = missingAttributes };
- }
-
- private class PresentMissingAttributes
- {
- public List Present { get; set; }
-
- public List Missing { get; set; }
+ return false;
}
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeAttributes.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeAttributes.cs
deleted file mode 100644
index b2020cea37..0000000000
--- a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeAttributes.cs
+++ /dev/null
@@ -1,25 +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.Collections.Generic;
-
-namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
-{
- ///
- /// Static creation methods for .
- ///
- public static class ModeAttributes
- {
- ///
- /// Creates an /
- ///
- public static ModeAttributes Create(TMode mode, string[] attributes)
- {
- return new ModeAttributes
- {
- Mode = mode,
- Attributes = attributes
- };
- }
- }
-}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeAttributesOfT.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeAttributesOfT.cs
index 997bf87926..2d06d04380 100644
--- a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeAttributesOfT.cs
+++ b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeAttributesOfT.cs
@@ -10,13 +10,24 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
public class ModeAttributes
{
///
- /// The 's mode.
+ /// Initializes a new instance of .
///
- public TMode Mode { get; set; }
+ /// The 's mode.
+ /// The names of attributes required for this mode.
+ public ModeAttributes(TMode mode, string[] attributes)
+ {
+ Mode = mode;
+ Attributes = attributes;
+ }
///
- /// The names of attributes required for this mode.
+ /// Gets the 's mode.
///
- public string[] Attributes { get; set; }
+ public TMode Mode { get; }
+
+ ///
+ /// Gets the names of attributes required for this mode.
+ ///
+ public string[] Attributes { get; }
}
}
diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeMatchAttributes.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeMatchAttributes.cs
deleted file mode 100644
index b10f3c6fa0..0000000000
--- a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeMatchAttributes.cs
+++ /dev/null
@@ -1,39 +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.Collections.Generic;
-
-namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
-{
- ///
- /// Static creation methods for .
- ///
- public static class ModeMatchAttributes
- {
- ///
- /// Creates an .
- ///
- public static ModeMatchAttributes Create(
- TMode mode,
- IList presentAttributes)
- {
- return Create(mode, presentAttributes, missingAttributes: null);
- }
-
- ///
- /// Creates an .
- ///
- public static ModeMatchAttributes Create(
- TMode mode,
- IList presentAttributes,
- IList missingAttributes)
- {
- return new ModeMatchAttributes
- {
- Mode = mode,
- PresentAttributes = presentAttributes,
- MissingAttributes = missingAttributes
- };
- }
- }
-}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeMatchAttributesOfT.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeMatchAttributesOfT.cs
deleted file mode 100644
index 6238181b4b..0000000000
--- a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeMatchAttributesOfT.cs
+++ /dev/null
@@ -1,29 +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.Collections.Generic;
-
-namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
-{
- ///
- /// A mapping of a mode to its missing and present attributes.
- ///
- /// The type representing the 's mode.
- public class ModeMatchAttributes
- {
- ///
- /// The 's mode.
- ///
- public TMode Mode { get; set; }
-
- ///
- /// The names of attributes that were present in this match.
- ///
- public IList PresentAttributes { get; set; }
-
- ///
- /// The names of attributes that were missing in this match.
- ///
- public IList MissingAttributes { get; set; }
- }
-}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeMatchResult.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeMatchResult.cs
deleted file mode 100644
index 94528fb3cb..0000000000
--- a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeMatchResult.cs
+++ /dev/null
@@ -1,30 +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.Collections.Generic;
-
-namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
-{
- ///
- /// Result of determining the mode an will run in.
- ///
- /// The type representing the 's mode.
- public class ModeMatchResult
- {
- ///
- /// Modes that were missing attributes but had at least one attribute present.
- ///
- public IList> PartialMatches { get; } = new List>();
-
- ///
- /// Modes that had all attributes present.
- ///
- public IList> FullMatches { get; } = new List>();
-
- ///
- /// Attributes that are present in at least one mode in , but in no modes in
- /// .
- ///
- public IList PartiallyMatchedAttributes { get; } = new List();
- }
-}
diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/LinkTagHelper.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/LinkTagHelper.cs
index 6650d9bc0a..89afb93467 100644
--- a/src/Microsoft.AspNet.Mvc.TagHelpers/LinkTagHelper.cs
+++ b/src/Microsoft.AspNet.Mvc.TagHelpers/LinkTagHelper.cs
@@ -3,7 +3,6 @@
using System;
using System.Diagnostics;
-using System.Globalization;
using System.Linq;
using System.Text.Encodings.Web;
using Microsoft.AspNet.Hosting;
@@ -11,10 +10,8 @@ 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.TagHelpers.Logging;
using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.Extensions.Caching.Memory;
-using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.TagHelpers
{
@@ -35,6 +32,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
[HtmlTargetElement("link", Attributes = AppendVersionAttributeName, TagStructure = TagStructure.WithoutEndTag)]
public class LinkTagHelper : UrlResolutionTagHelper
{
+
private static readonly string FallbackJavaScriptResourceName =
typeof(LinkTagHelper).Namespace + ".compiler.resources.LinkTagHelper_FallbackJavaScript.js";
@@ -48,19 +46,21 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
private const string FallbackTestValueAttributeName = "asp-fallback-test-value";
private const string AppendVersionAttributeName = "asp-append-version";
private const string HrefAttributeName = "href";
+ private static readonly Func Compare = (a, b) => a - b;
private FileVersionProvider _fileVersionProvider;
private static readonly ModeAttributes[] ModeDetails = new[] {
// Regular src with file version alone
- ModeAttributes.Create(Mode.AppendVersion, new[] { AppendVersionAttributeName }),
+ new ModeAttributes(Mode.AppendVersion, new[] { AppendVersionAttributeName }),
// Globbed Href (include only) no static href
- ModeAttributes.Create(Mode.GlobbedHref, new [] { HrefIncludeAttributeName }),
+ new ModeAttributes(Mode.GlobbedHref, new [] { HrefIncludeAttributeName }),
// Globbed Href (include & exclude), no static href
- ModeAttributes.Create(Mode.GlobbedHref, new [] { HrefIncludeAttributeName, HrefExcludeAttributeName }),
+ new ModeAttributes(Mode.GlobbedHref, new [] { HrefIncludeAttributeName, HrefExcludeAttributeName }),
// Fallback with static href
- ModeAttributes.Create(
- Mode.Fallback, new[]
+ new ModeAttributes(
+ Mode.Fallback,
+ new[]
{
FallbackHrefAttributeName,
FallbackTestClassAttributeName,
@@ -68,16 +68,20 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
FallbackTestValueAttributeName
}),
// Fallback with globbed href (include only)
- ModeAttributes.Create(
- Mode.Fallback, new[] {
+ new ModeAttributes(
+ Mode.Fallback,
+ new[]
+ {
FallbackHrefIncludeAttributeName,
FallbackTestClassAttributeName,
FallbackTestPropertyAttributeName,
FallbackTestValueAttributeName
}),
// Fallback with globbed href (include & exclude)
- ModeAttributes.Create(
- Mode.Fallback, new[] {
+ new ModeAttributes(
+ Mode.Fallback,
+ new[]
+ {
FallbackHrefIncludeAttributeName,
FallbackHrefExcludeAttributeName,
FallbackTestClassAttributeName,
@@ -89,14 +93,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
///
/// Creates a new .
///
- /// The .
/// The .
/// The .
/// The .
/// The .
/// The .
public LinkTagHelper(
- ILogger logger,
IHostingEnvironment hostingEnvironment,
IMemoryCache cache,
HtmlEncoder htmlEncoder,
@@ -104,7 +106,6 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
IUrlHelperFactory urlHelperFactory)
: base(urlHelperFactory, htmlEncoder)
{
- Logger = logger;
HostingEnvironment = hostingEnvironment;
Cache = cache;
JavaScriptEncoder = javaScriptEncoder;
@@ -199,8 +200,6 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
[HtmlAttributeName(FallbackTestValueAttributeName)]
public string FallbackTestValue { get; set; }
- protected ILogger Logger { get; }
-
protected IHostingEnvironment HostingEnvironment { get; }
protected IMemoryCache Cache { get; }
@@ -237,10 +236,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// not function properly.
Href = output.Attributes[HrefAttributeName]?.Value as string;
- var modeResult = AttributeMatcher.DetermineMode(context, ModeDetails);
- Logger.TagHelperModeMatchResult(modeResult, context.UniqueId, ViewContext.View.Path, this);
-
- if (modeResult.FullMatches.Count == 0)
+ Mode mode;
+ if (!AttributeMatcher.TryDetermineMode(context, ModeDetails, Compare, out mode))
{
// No attributes matched so we have nothing to do
return;
@@ -260,18 +257,6 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}
var builder = new DefaultTagHelperContent();
-
- // Get the highest matched mode
- var mode = modeResult.FullMatches[0].Mode;
- for (var i = 1; i < modeResult.FullMatches.Count; i++)
- {
- var currentMode = modeResult.FullMatches[i].Mode;
- if (mode < currentMode)
- {
- mode = currentMode;
- }
- }
-
if (mode == Mode.GlobbedHref || mode == Mode.Fallback && !string.IsNullOrEmpty(HrefInclude))
{
BuildGlobbedLinkTags(attributes, builder);
diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/Logging/ModeMatchResultLoggerExtensions.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/Logging/ModeMatchResultLoggerExtensions.cs
deleted file mode 100644
index 1ac481774f..0000000000
--- a/src/Microsoft.AspNet.Mvc.TagHelpers/Logging/ModeMatchResultLoggerExtensions.cs
+++ /dev/null
@@ -1,127 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Microsoft.AspNet.Mvc.TagHelpers.Internal;
-using Microsoft.AspNet.Razor.TagHelpers;
-using Microsoft.Extensions.Logging;
-
-namespace Microsoft.AspNet.Mvc.TagHelpers.Logging
-{
- internal static class ModeMatchResultLoggerExtensions
- {
- private static readonly Action _skippingProcessing;
-
- static ModeMatchResultLoggerExtensions()
- {
- _skippingProcessing = LoggerMessage.Define(
- LogLevel.Debug,
- 1,
- "Skipping processing for tag helper '{TagHelper}' with id '{TagHelperId}'.");
- }
-
- public static void TagHelperModeMatchResult(
- this ILogger logger,
- ModeMatchResult modeMatchResult,
- string uniqueId,
- string viewPath,
- ITagHelper tagHelper)
- {
- if (logger.IsEnabled(LogLevel.Warning) && modeMatchResult.PartiallyMatchedAttributes.Count > 0)
- {
- // Build the list of partial matches that contain attributes not appearing in at least one full match
- var partialOnlyMatches = new List>();
- for (var i = 0; i < modeMatchResult.PartialMatches.Count; i++)
- {
- var presentAttributes = modeMatchResult.PartialMatches[i].PresentAttributes;
- for (var j = 0; j < presentAttributes.Count; j++)
- {
- var present = presentAttributes[j];
- var presentIsPartialOnlyMatch = false;
- for (var k = 0; k < modeMatchResult.PartiallyMatchedAttributes.Count; k++)
- {
- var partiallyMatched = modeMatchResult.PartiallyMatchedAttributes[k];
- if (string.Equals(partiallyMatched, present, StringComparison.OrdinalIgnoreCase))
- {
- presentIsPartialOnlyMatch = true;
- break;
- }
- }
-
- if (presentIsPartialOnlyMatch)
- {
- partialOnlyMatches.Add(modeMatchResult.PartialMatches[i]);
- break;
- }
- }
- }
-
- var logValues = new PartialModeMatchLogValues(
- uniqueId,
- viewPath,
- partialOnlyMatches);
-
- logger.LogWarning(logValues);
- }
-
- if (logger.IsEnabled(LogLevel.Debug) && modeMatchResult.FullMatches.Count == 0)
- {
- _skippingProcessing(logger, tagHelper, uniqueId, null);
- }
- }
-
- ///
- /// Log values for instances that opt out
- /// of processing due to missing attributes for one of several possible modes.
- ///
- private class PartialModeMatchLogValues : ILogValues
- {
- private readonly IEnumerable> _partialMatches;
- private readonly string _uniqueId;
- private readonly string _viewPath;
-
- ///
- /// Creates a new .
- ///
- ///
- /// The unique ID of the HTML element this message applies to.
- ///
- /// The path to the view.
- /// The set of modes with partial required attributes.
- public PartialModeMatchLogValues(
- string uniqueId,
- string viewPath,
- IEnumerable> partialMatches)
- {
- if (partialMatches == null)
- {
- throw new ArgumentNullException(nameof(partialMatches));
- }
-
- _uniqueId = uniqueId;
- _viewPath = viewPath;
- _partialMatches = partialMatches;
- }
-
- public IEnumerable> GetValues()
- {
- yield return new KeyValuePair(
- "Message",
- "Tag helper had partial matches while determining mode.");
- yield return new KeyValuePair("UniqueId", _uniqueId);
- yield return new KeyValuePair("ViewPath", _viewPath);
- yield return new KeyValuePair("PartialMatches", _partialMatches);
- }
-
- public override string ToString()
- {
- var newLine = Environment.NewLine;
- return string.Format(
- $"Tag Helper with ID '{_uniqueId}' in view '{_viewPath}' had partial matches " +
- $"while determining mode:{newLine}\t{{0}}",
- string.Join($"{newLine}\t", _partialMatches.Select(partial =>
- string.Format($"Mode '{partial.Mode}' missing attributes:{newLine}\t\t{{0}} ",
- string.Join($"{newLine}\t\t", partial.MissingAttributes)))));
- }
- }
- }
-}
diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/ScriptTagHelper.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/ScriptTagHelper.cs
index dbe7cbe1a0..39edb15082 100644
--- a/src/Microsoft.AspNet.Mvc.TagHelpers/ScriptTagHelper.cs
+++ b/src/Microsoft.AspNet.Mvc.TagHelpers/ScriptTagHelper.cs
@@ -9,11 +9,8 @@ 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.TagHelpers.Logging;
-using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.Extensions.Caching.Memory;
-using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Mvc.TagHelpers
{
@@ -40,32 +37,36 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
private const string FallbackTestExpressionAttributeName = "asp-fallback-test";
private const string SrcAttributeName = "src";
private const string AppendVersionAttributeName = "asp-append-version";
-
+ private static readonly Func Compare = (a, b) => a - b;
private FileVersionProvider _fileVersionProvider;
private static readonly ModeAttributes[] ModeDetails = new[] {
// Regular src with file version alone
- ModeAttributes.Create(Mode.AppendVersion, new[] { AppendVersionAttributeName }),
+ new ModeAttributes(Mode.AppendVersion, new[] { AppendVersionAttributeName }),
// Globbed src (include only)
- ModeAttributes.Create(Mode.GlobbedSrc, new [] { SrcIncludeAttributeName }),
+ new ModeAttributes(Mode.GlobbedSrc, new [] { SrcIncludeAttributeName }),
// Globbed src (include & exclude)
- ModeAttributes.Create(Mode.GlobbedSrc, new [] { SrcIncludeAttributeName, SrcExcludeAttributeName }),
+ new ModeAttributes(Mode.GlobbedSrc, new [] { SrcIncludeAttributeName, SrcExcludeAttributeName }),
// Fallback with static src
- ModeAttributes.Create(
- Mode.Fallback, new[]
+ new ModeAttributes(Mode.Fallback,
+ new[]
{
FallbackSrcAttributeName,
FallbackTestExpressionAttributeName
}),
// Fallback with globbed src (include only)
- ModeAttributes.Create(
- Mode.Fallback, new[] {
+ new ModeAttributes(
+ Mode.Fallback,
+ new[]
+ {
FallbackSrcIncludeAttributeName,
FallbackTestExpressionAttributeName
}),
// Fallback with globbed src (include & exclude)
- ModeAttributes.Create(
- Mode.Fallback, new[] {
+ new ModeAttributes(
+ Mode.Fallback,
+ new[]
+ {
FallbackSrcIncludeAttributeName,
FallbackSrcExcludeAttributeName,
FallbackTestExpressionAttributeName
@@ -75,14 +76,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
///
/// Creates a new .
///
- /// The .
/// The .
/// The .
/// The .
/// The .
/// The .
public ScriptTagHelper(
- ILogger logger,
IHostingEnvironment hostingEnvironment,
IMemoryCache cache,
HtmlEncoder htmlEncoder,
@@ -90,7 +89,6 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
IUrlHelperFactory urlHelperFactory)
: base(urlHelperFactory, htmlEncoder)
{
- Logger = logger;
HostingEnvironment = hostingEnvironment;
Cache = cache;
JavaScriptEncoder = javaScriptEncoder;
@@ -167,8 +165,6 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
[HtmlAttributeName(FallbackTestExpressionAttributeName)]
public string FallbackTestExpression { get; set; }
- protected ILogger Logger { get; }
-
protected IHostingEnvironment HostingEnvironment { get; }
protected IMemoryCache Cache { get; }
@@ -205,10 +201,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
// not function properly.
Src = output.Attributes[SrcAttributeName]?.Value as string;
- var modeResult = AttributeMatcher.DetermineMode(context, ModeDetails);
- Logger.TagHelperModeMatchResult(modeResult, context.UniqueId, ViewContext.View.Path, this);
-
- if (modeResult.FullMatches.Count == 0)
+ Mode mode;
+ if (!AttributeMatcher.TryDetermineMode(context, ModeDetails, Compare, out mode))
{
// No attributes matched so we have nothing to do
return;
@@ -229,17 +223,6 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var builder = new DefaultTagHelperContent();
- // Get the highest matched mode
- var mode = modeResult.FullMatches[0].Mode;
- for (var i = 1; i < modeResult.FullMatches.Count; i++)
- {
- var currentMode = modeResult.FullMatches[i].Mode;
- if (mode < currentMode)
- {
- mode = currentMode;
- }
- }
-
if (mode == Mode.GlobbedSrc || mode == Mode.Fallback && !string.IsNullOrEmpty(SrcInclude))
{
BuildGlobbedScriptTags(attributes, builder);
diff --git a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/Internal/AttributeMatcherTest.cs b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/Internal/AttributeMatcherTest.cs
index d6bc0c0d39..7eafa61c46 100644
--- a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/Internal/AttributeMatcherTest.cs
+++ b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/Internal/AttributeMatcherTest.cs
@@ -10,13 +10,17 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
{
public class AttributeMatcherTest
{
- [Fact]
- public void DetermineMode_FindsFullModeMatchWithSingleAttribute()
+ private static readonly Func Compare = (a, b) => a - b;
+
+ [Theory]
+ [InlineData(new object[] { new[] { "required-attr" } })]
+ [InlineData(new object[] { new[] { "first-attr", "second-attr" } })]
+ public void TryDetermineMode_ReturnsFalseIfNoAttributeMatchesAllRequiredAttributes(string[] modeAttributes)
{
// Arrange
- var modeInfo = new[]
+ var modeInfos = new[]
{
- ModeAttributes.Create("mode0", new [] { "first-attr" })
+ new ModeAttributes(Mode.A, modeAttributes)
};
var attributes = new TagHelperAttributeList
{
@@ -26,25 +30,22 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
var context = MakeTagHelperContext(attributes);
// Act
- var modeMatch = AttributeMatcher.DetermineMode(context, modeInfo);
+ Mode result;
+ var modeMatch = AttributeMatcher.TryDetermineMode(context, modeInfos, Compare, out result);
// Assert
- Assert.Collection(modeMatch.FullMatches, match =>
- {
- Assert.Equal("mode0", match.Mode);
- Assert.Collection(match.PresentAttributes, attribute => Assert.Equal("first-attr", attribute));
- });
- Assert.Empty(modeMatch.PartialMatches);
- Assert.Empty(modeMatch.PartiallyMatchedAttributes);
+ Assert.False(modeMatch);
}
[Fact]
- public void DetermineMode_FindsFullModeMatchWithMultipleAttributes()
+ public void DetermineMode_SetsModeIfAllAttributesMatch()
{
// Arrange
- var modeInfo = new[]
+ var modeInfos = new[]
{
- ModeAttributes.Create("mode0", new [] { "first-attr", "second-attr" })
+ new ModeAttributes(Mode.A, new[] { "a-required-attributes" }),
+ new ModeAttributes(Mode.B, new[] { "first-attr", "second-attr" }),
+ new ModeAttributes(Mode.C, new[] { "first-attr", "third-attr" }),
};
var attributes = new TagHelperAttributeList
{
@@ -55,34 +56,28 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
var context = MakeTagHelperContext(attributes);
// Act
- var modeMatch = AttributeMatcher.DetermineMode(context, modeInfo);
+ Mode result;
+ var modeMatch = AttributeMatcher.TryDetermineMode(context, modeInfos, Compare, out result);
// Assert
- Assert.Collection(modeMatch.FullMatches, match =>
- {
- Assert.Equal("mode0", match.Mode);
- Assert.Collection(match.PresentAttributes,
- attribute => Assert.Equal("first-attr", attribute),
- attribute => Assert.Equal("second-attr", attribute)
- );
- });
- Assert.Empty(modeMatch.PartialMatches);
- Assert.Empty(modeMatch.PartiallyMatchedAttributes);
+ Assert.True(modeMatch);
+ Assert.Equal(Mode.B, result);
}
[Fact]
- public void DetermineMode_FindsFullAndPartialModeMatchWithMultipleAttribute()
+ public void DetermineMode_SetsModeWithHigestValue()
{
// Arrange
- var modeInfo = new[]
+ var modeInfos = new[]
{
- ModeAttributes.Create("mode0", new [] { "second-attr" }),
- ModeAttributes.Create("mode1", new [] { "first-attr", "third-attr" }),
- ModeAttributes.Create("mode2", new [] { "first-attr", "second-attr", "third-attr" }),
- ModeAttributes.Create("mode3", new [] { "fourth-attr" })
+ new ModeAttributes(Mode.A, new[] { "first-attr" }),
+ new ModeAttributes(Mode.B, new[] { "first-attr", "second-attr" }),
+ new ModeAttributes(Mode.D, new[] { "second-attr", "third-attr" }),
+ new ModeAttributes(Mode.C, new[] { "first-attr", "second-attr", "third-attr" }),
};
var attributes = new TagHelperAttributeList
{
+ ["first-attr"] = "value",
["second-attr"] = "value",
["third-attr"] = "value",
["not-in-any-mode"] = "value"
@@ -90,43 +85,28 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
var context = MakeTagHelperContext(attributes);
// Act
- var modeMatch = AttributeMatcher.DetermineMode(context, modeInfo);
+ Mode result;
+ var modeMatch = AttributeMatcher.TryDetermineMode(context, modeInfos, Compare, out result);
// Assert
- Assert.Collection(modeMatch.FullMatches, match =>
- {
- Assert.Equal("mode0", match.Mode);
- Assert.Collection(match.PresentAttributes, attribute => Assert.Equal("second-attr", attribute));
- });
- Assert.Collection(modeMatch.PartialMatches,
- match =>
- {
- Assert.Equal("mode1", match.Mode);
- Assert.Collection(match.PresentAttributes, attribute => Assert.Equal("third-attr", attribute));
- Assert.Collection(match.MissingAttributes, attribute => Assert.Equal("first-attr", attribute));
- },
- match =>
- {
- Assert.Equal("mode2", match.Mode);
- Assert.Collection(match.PresentAttributes,
- attribute => Assert.Equal("second-attr", attribute),
- attribute => Assert.Equal("third-attr", attribute)
- );
- Assert.Collection(match.MissingAttributes, attribute => Assert.Equal("first-attr", attribute));
- });
- Assert.Collection(modeMatch.PartiallyMatchedAttributes, attribute => Assert.Equal("third-attr", attribute));
+ Assert.True(modeMatch);
+ Assert.Equal(Mode.D, result);
}
- private static TagHelperContext MakeTagHelperContext(
- TagHelperAttributeList attributes = null,
- string content = null)
+ private static TagHelperContext MakeTagHelperContext(TagHelperAttributeList attributes)
{
- attributes = attributes ?? new TagHelperAttributeList();
-
return new TagHelperContext(
attributes,
items: new Dictionary