diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/AttributeMatcher.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/AttributeMatcher.cs
index 9f181d1ab9..7608782758 100644
--- a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/AttributeMatcher.cs
+++ b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/AttributeMatcher.cs
@@ -19,18 +19,20 @@ public static class AttributeMatcher
/// Determines whether a 's required attributes are present, non null, non empty, and
/// non whitepsace.
///
- /// The .
+ /// The .
+ /// The .
///
/// The attributes the requires in order to run.
///
/// An optional to log warning details to.
/// A indicating whether the should run.
public static bool AllRequiredAttributesArePresent(
- [NotNull] TagHelperContext context,
+ [NotNull] TagHelperContext tagHelperContext,
+ [NotNull] ViewContext viewContext,
[NotNull] IEnumerable requiredAttributes,
ILogger logger)
{
- var attributes = GetPresentMissingAttributes(context, requiredAttributes);
+ var attributes = GetPresentMissingAttributes(tagHelperContext, requiredAttributes);
if (attributes.Missing.Any())
{
@@ -38,7 +40,10 @@ public static class AttributeMatcher
{
// At least 1 attribute was present indicating the user intended to use the tag helper,
// but at least 1 was missing too, so log a warning with the details.
- logger.WriteWarning(new MissingAttributeLoggerStructure(context.UniqueId, attributes.Missing));
+ logger.WriteWarning(new MissingAttributeLoggerStructure(
+ tagHelperContext.UniqueId,
+ viewContext.View.Path,
+ attributes.Missing));
}
return false;
diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/MissingAttributeLoggerStructure.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/MissingAttributeLoggerStructure.cs
index b5818101c6..44f7dda5dc 100644
--- a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/MissingAttributeLoggerStructure.cs
+++ b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/MissingAttributeLoggerStructure.cs
@@ -14,8 +14,9 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
public class MissingAttributeLoggerStructure : ILoggerStructure
{
private readonly string _uniqueId;
+ private readonly string _viewPath;
private readonly IEnumerable> _values;
-
+
// Internal for unit testing
internal IEnumerable MissingAttributes { get; }
@@ -23,14 +24,17 @@ public class MissingAttributeLoggerStructure : ILoggerStructure
/// Creates a new .
///
/// The unique ID of the HTML element this message applies to.
+ /// The path to the view.
/// The missing required attributes.
- public MissingAttributeLoggerStructure(string uniqueId, IEnumerable missingAttributes)
+ public MissingAttributeLoggerStructure(string uniqueId, string viewPath, IEnumerable missingAttributes)
{
_uniqueId = uniqueId;
+ _viewPath = viewPath;
MissingAttributes = missingAttributes;
_values = new Dictionary
{
["UniqueId"] = _uniqueId,
+ ["ViewPath"] = _viewPath,
["MissingAttributes"] = MissingAttributes
};
}
@@ -61,8 +65,9 @@ public string Message
/// The message.
public string Format()
{
- return string.Format("Tag Helper unique ID: {0}, Missing attributes: {1}",
+ return string.Format("Tag Helper with ID {0} in view '{1}' is missing attributes: {2}",
_uniqueId,
+ _viewPath,
string.Join(",", MissingAttributes));
}
}
diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeMatchResult.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeMatchResult.cs
index bc6dc275bf..d7c1735d6c 100644
--- a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeMatchResult.cs
+++ b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/ModeMatchResult.cs
@@ -39,7 +39,12 @@ public class ModeMatchResult
/// The .
/// The .
/// The value of .
- public void LogDetails([NotNull] ILogger logger, [NotNull] TTagHelper tagHelper, string uniqueId)
+ /// The path to the view the is on.
+ public void LogDetails(
+ [NotNull] ILogger logger,
+ [NotNull] TTagHelper tagHelper,
+ string uniqueId,
+ string viewPath)
where TTagHelper : ITagHelper
{
if (logger.IsEnabled(LogLevel.Warning) && PartiallyMatchedAttributes.Any())
@@ -50,7 +55,7 @@ public void LogDetails([NotNull] ILogger logger, [NotNull] TTagHelpe
attribute => PartiallyMatchedAttributes.Contains(
attribute, StringComparer.OrdinalIgnoreCase)));
- logger.WriteWarning(new PartialModeMatchLoggerStructure(uniqueId, partialOnlyMatches));
+ logger.WriteWarning(new PartialModeMatchLoggerStructure(uniqueId, viewPath, partialOnlyMatches));
}
if (logger.IsEnabled(LogLevel.Verbose) && !FullMatches.Any())
diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/PartialAttributeLoggerStructure.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/PartialAttributeLoggerStructure.cs
index 395294d108..12f1cd8f05 100644
--- a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/PartialAttributeLoggerStructure.cs
+++ b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/PartialAttributeLoggerStructure.cs
@@ -17,6 +17,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
public class PartialModeMatchLoggerStructure : ILoggerStructure
{
private readonly string _uniqueId;
+ private readonly string _viewPath;
private readonly IEnumerable> _partialMatches;
private readonly IEnumerable> _values;
@@ -24,16 +25,20 @@ public class PartialModeMatchLoggerStructure : ILoggerStructure
/// 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 PartialModeMatchLoggerStructure(
string uniqueId,
+ string viewPath,
[NotNull] IEnumerable> partialMatches)
{
_uniqueId = uniqueId;
+ _viewPath = viewPath;
_partialMatches = partialMatches;
_values = new Dictionary
{
["UniqueId"] = _uniqueId,
+ ["ViewPath"] = _viewPath,
["PartialMatches"] = partialMatches
};
}
@@ -65,8 +70,8 @@ public string Message
public string Format()
{
var newLine = Environment.NewLine;
- return
- string.Format($"Tag Helper {_uniqueId} had partial matches while determining mode:{newLine}\t{{0}}",
+ 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/LinkTagHelper.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/LinkTagHelper.cs
index 8b46283489..91cc7707cb 100644
--- a/src/Microsoft.AspNet.Mvc.TagHelpers/LinkTagHelper.cs
+++ b/src/Microsoft.AspNet.Mvc.TagHelpers/LinkTagHelper.cs
@@ -164,7 +164,7 @@ public override void Process(TagHelperContext context, TagHelperOutput output)
Debug.Assert(modeResult.FullMatches.Select(match => match.Mode).Distinct().Count() <= 1,
$"There should only be one mode match, check the {nameof(ModeDetails)}");
- modeResult.LogDetails(Logger, this, context.UniqueId);
+ modeResult.LogDetails(Logger, this, context.UniqueId, ViewContext.View.Path);
if (!modeResult.FullMatches.Any())
{
diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/ScriptTagHelper.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/ScriptTagHelper.cs
index 1afc889517..975209caba 100644
--- a/src/Microsoft.AspNet.Mvc.TagHelpers/ScriptTagHelper.cs
+++ b/src/Microsoft.AspNet.Mvc.TagHelpers/ScriptTagHelper.cs
@@ -50,14 +50,21 @@ public class ScriptTagHelper : TagHelper
[Activate]
protected internal ILogger Logger { get; set; }
+ [Activate]
+ protected internal ViewContext ViewContext { get; set; }
+
///
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
- if (!AttributeMatcher.AllRequiredAttributesArePresent(context, RequiredAttributes, Logger))
+ if (!AttributeMatcher.AllRequiredAttributesArePresent(context, ViewContext, RequiredAttributes, Logger))
{
if (Logger.IsEnabled(LogLevel.Verbose))
{
- Logger.WriteVerbose("Skipping processing for {0} {1}", nameof(ScriptTagHelper), context.UniqueId);
+ Logger.WriteVerbose(
+ "Skipping processing for {0} with ID {1} on view '{2}'",
+ nameof(ScriptTagHelper),
+ context.UniqueId,
+ ViewContext.View.Path);
}
return;
diff --git a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/Internal/ModeMatchResultTest.cs b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/Internal/ModeMatchResultTest.cs
index 042a555429..0cbb16c5bb 100644
--- a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/Internal/ModeMatchResultTest.cs
+++ b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/Internal/ModeMatchResultTest.cs
@@ -19,9 +19,10 @@ public void LogDetails_LogsVerboseWhenNoFullMatchesFound()
var logger = MakeLogger(LogLevel.Verbose);
var tagHelper = new Mock();
var uniqueId = "id";
+ var viewPath = "Views/Home/Index.cshtml";
// Act
- modeMatchResult.LogDetails(logger, tagHelper.Object, uniqueId);
+ modeMatchResult.LogDetails(logger, tagHelper.Object, uniqueId, viewPath);
// Assert
Mock.Get(logger).Verify(l => l.Write(
@@ -44,9 +45,10 @@ public void LogDetails_DoesNotLogWhenPartialMatchFoundButNoPartiallyMatchedAttri
var logger = MakeLogger(LogLevel.Verbose);
var tagHelper = new Mock();
var uniqueId = "id";
+ var viewPath = "Views/Home/Index.cshtml";
// Act
- modeMatchResult.LogDetails(logger, tagHelper.Object, uniqueId);
+ modeMatchResult.LogDetails(logger, tagHelper.Object, uniqueId, viewPath);
// Assert
Mock.Get(logger).Verify(l => l.Write(
@@ -74,9 +76,10 @@ public void LogDetails_LogsWhenPartiallyMatchedAttributesFound()
var logger = MakeLogger(LogLevel.Verbose);
var tagHelper = new Mock();
var uniqueId = "id";
+ var viewPath = "Views/Home/Index.cshtml";
// Act
- modeMatchResult.LogDetails(logger, tagHelper.Object, uniqueId);
+ modeMatchResult.LogDetails(logger, tagHelper.Object, uniqueId, viewPath);
// Assert
Mock.Get(logger).Verify(l => l.Write(
@@ -104,9 +107,10 @@ public void LogDetails_DoesNotLogWhenLoggingLevelIsSetAboveWarning()
var logger = MakeLogger(LogLevel.Critical);
var tagHelper = new Mock();
var uniqueId = "id";
+ var viewPath = "Views/Home/Index.cshtml";
// Act
- modeMatchResult.LogDetails(logger, tagHelper.Object, uniqueId);
+ modeMatchResult.LogDetails(logger, tagHelper.Object, uniqueId, viewPath);
// Assert
Mock.Get(logger).Verify(l => l.Write(
diff --git a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs
index c8f4b5e0d5..ce0d41f4e0 100644
--- a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs
+++ b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs
@@ -3,11 +3,17 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using Microsoft.AspNet.Http.Core;
+using Microsoft.AspNet.Mvc.ModelBinding;
+using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.TagHelpers.Internal;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
+using Microsoft.AspNet.Routing;
using Microsoft.Framework.Logging;
+using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.TagHelpers
@@ -31,7 +37,8 @@ public async Task RunsWhenRequiredAttributesArePresent(string srcValue)
attributes.Add("src", srcValue);
}
- var context = MakeTagHelperContext(attributes);
+ var tagHelperContext = MakeTagHelperContext(attributes);
+ var viewContext = MakeViewContext();
var output = MakeTagHelperOutput("script");
var logger = CreateLogger();
@@ -39,12 +46,13 @@ public async Task RunsWhenRequiredAttributesArePresent(string srcValue)
var helper = new ScriptTagHelper()
{
Logger = logger,
+ ViewContext = viewContext,
FallbackSrc = "http://www.example.com/blank.js",
FallbackTestExpression = "isavailable()",
};
// Act
- await helper.ProcessAsync(context, output);
+ await helper.ProcessAsync(tagHelperContext, output);
// Assert
Assert.Null(output.TagName);
@@ -96,15 +104,17 @@ public static TheoryData MissingAttributeDataSet
// Arrange
Assert.Single(attributes);
- var context = MakeTagHelperContext(attributes);
+ var tagHelperContext = MakeTagHelperContext(attributes);
+ var viewContext = MakeViewContext();
var output = MakeTagHelperOutput("script");
var logger = CreateLogger();
helper.Logger = logger;
+ helper.ViewContext = viewContext;
// Act
- await helper.ProcessAsync(context, output);
+ await helper.ProcessAsync(tagHelperContext, output);
// Assert
Assert.Equal("script", output.TagName);
@@ -115,17 +125,19 @@ public static TheoryData MissingAttributeDataSet
public async Task DoesNotRunWhenAllRequiredAttributesAreMissing()
{
// Arrange
- var context = MakeTagHelperContext();
+ var tagHelperContext = MakeTagHelperContext();
+ var viewContext = MakeViewContext();
var output = MakeTagHelperOutput("script");
var logger = CreateLogger();
var helper = new ScriptTagHelper
{
Logger = logger,
+ ViewContext = viewContext
};
// Act
- await helper.ProcessAsync(context, output);
+ await helper.ProcessAsync(tagHelperContext, output);
// Assert
Assert.Equal("script", output.TagName);
@@ -142,15 +154,17 @@ public async Task DoesNotRunWhenAllRequiredAttributesAreMissing()
// Arrange
Assert.Single(attributes);
- var context = MakeTagHelperContext(attributes);
+ var tagHelperContext = MakeTagHelperContext(attributes);
+ var viewContext = MakeViewContext();
var output = MakeTagHelperOutput("script");
var logger = CreateLogger();
helper.Logger = logger;
+ helper.ViewContext = viewContext;
// Act
- await helper.ProcessAsync(context, output);
+ await helper.ProcessAsync(tagHelperContext, output);
// Assert
Assert.Equal("script", output.TagName);
@@ -175,17 +189,19 @@ public async Task DoesNotRunWhenAllRequiredAttributesAreMissing()
public async Task LogsWhenAllRequiredAttributesAreMissing()
{
// Arrange
- var context = MakeTagHelperContext();
+ var tagHelperContext = MakeTagHelperContext();
+ var viewContext = MakeViewContext();
var output = MakeTagHelperOutput("script");
var logger = CreateLogger();
var helper = new ScriptTagHelper
{
Logger = logger,
+ ViewContext = viewContext
};
// Act
- await helper.ProcessAsync(context, output);
+ await helper.ProcessAsync(tagHelperContext, output);
// Assert
Assert.Equal("script", output.TagName);
@@ -203,7 +219,7 @@ public async Task LogsWhenAllRequiredAttributesAreMissing()
public async Task PreservesOrderOfSourceAttributesWhenRun()
{
// Arrange
- var context = MakeTagHelperContext(
+ var tagHelperContext = MakeTagHelperContext(
attributes: new Dictionary
{
["data-extra"] = "something",
@@ -213,6 +229,8 @@ public async Task PreservesOrderOfSourceAttributesWhenRun()
["asp-fallback-test"] = "isavailable()",
});
+ var viewContext = MakeViewContext();
+
var output = MakeTagHelperOutput("link",
attributes: new Dictionary
{
@@ -226,12 +244,13 @@ public async Task PreservesOrderOfSourceAttributesWhenRun()
var helper = new ScriptTagHelper
{
Logger = logger,
+ ViewContext = viewContext,
FallbackSrc = "~/blank.js",
FallbackTestExpression = "http://www.example.com/blank.js",
};
// Act
- await helper.ProcessAsync(context, output);
+ await helper.ProcessAsync(tagHelperContext, output);
// Assert
Assert.StartsWith("