diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorParser.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorParser.cs
index 4d87d4a1ff..94a0faf16d 100644
--- a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorParser.cs
+++ b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorParser.cs
@@ -16,7 +16,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{
///
/// A subtype of that uses to support inheritance of tag
- /// helpers from _ViewStart files.
+ /// helpers from _GlobalImport files.
///
public class MvcRazorParser : RazorParser
{
@@ -27,16 +27,19 @@ namespace Microsoft.AspNet.Mvc.Razor
///
/// The to copy properties from.
/// The s that are inherited
- /// from parsed pages from _ViewStart files.
+ /// from parsed pages from _GlobalImport files.
/// The inherited by
/// default by all Razor pages in the application.
- public MvcRazorParser([NotNull] RazorParser parser,
- [NotNull] IReadOnlyList inheritedCodeTrees,
- [NotNull] IReadOnlyList defaultInheritedChunks)
+ public MvcRazorParser(
+ [NotNull] RazorParser parser,
+ [NotNull] IReadOnlyList inheritedCodeTrees,
+ [NotNull] IReadOnlyList defaultInheritedChunks)
: base(parser)
{
- // Construct tag helper descriptors from @addTagHelper and @removeTagHelper chunks
- _globalImportDirectiveDescriptors = GetTagHelperDirectiveDescriptors(inheritedCodeTrees, defaultInheritedChunks);
+ // Construct tag helper descriptors from @addTagHelper, @removeTagHelper and @tagHelperPrefix chunks
+ _globalImportDirectiveDescriptors = GetTagHelperDirectiveDescriptors(
+ inheritedCodeTrees,
+ defaultInheritedChunks);
}
///
@@ -44,7 +47,7 @@ namespace Microsoft.AspNet.Mvc.Razor
[NotNull] Block documentRoot,
[NotNull] ParserErrorSink errorSink)
{
- var visitor = new GlobalImportAddRemoveTagHelperVisitor(
+ var visitor = new GlobalImportTagHelperDirectiveSpanVisitor(
TagHelperDescriptorResolver,
_globalImportDirectiveDescriptors,
errorSink);
@@ -58,43 +61,63 @@ namespace Microsoft.AspNet.Mvc.Razor
var descriptors = new List();
// For tag helpers, the @removeTagHelper only applies tag helpers that were added prior to it.
- // Consequently we must visit tag helpers outside-in - furthest _ViewStart first and nearest one last. This
- // is different from the behavior of chunk merging where we visit the nearest one first and ignore chunks
- // that were previously visited.
- var chunksFromViewStarts = inheritedCodeTrees.Reverse()
- .SelectMany(tree => tree.Chunks);
- var chunksInOrder = defaultInheritedChunks.Concat(chunksFromViewStarts);
+ // Consequently we must visit tag helpers outside-in - furthest _GlobalImport first and nearest one last.
+ // This is different from the behavior of chunk merging where we visit the nearest one first and ignore
+ // chunks that were previously visited.
+ var chunksFromGlobalImports = inheritedCodeTrees
+ .Reverse()
+ .SelectMany(tree => tree.Chunks);
+ var chunksInOrder = defaultInheritedChunks.Concat(chunksFromGlobalImports);
foreach (var chunk in chunksInOrder)
{
- var addHelperChunk = chunk as AddTagHelperChunk;
- if (addHelperChunk != null)
+ // All TagHelperDirectiveDescriptors created here have undefined source locations because the source
+ // that created them is not in the same file.
+ var addTagHelperChunk = chunk as AddTagHelperChunk;
+ if (addTagHelperChunk != null)
{
- var descriptor = new TagHelperDirectiveDescriptor(addHelperChunk.LookupText,
- SourceLocation.Undefined,
- TagHelperDirectiveType.AddTagHelper);
+ var descriptor = new TagHelperDirectiveDescriptor(
+ addTagHelperChunk.LookupText,
+ SourceLocation.Undefined,
+ TagHelperDirectiveType.AddTagHelper);
+
descriptors.Add(descriptor);
+
+ continue;
}
- else
+
+ var removeTagHelperChunk = chunk as RemoveTagHelperChunk;
+ if (removeTagHelperChunk != null)
{
- var removeHelperChunk = chunk as RemoveTagHelperChunk;
- if (removeHelperChunk != null)
- {
- var descriptor = new TagHelperDirectiveDescriptor(removeHelperChunk.LookupText,
- SourceLocation.Undefined,
- TagHelperDirectiveType.RemoveTagHelper);
- descriptors.Add(descriptor);
- }
+ var descriptor = new TagHelperDirectiveDescriptor(
+ removeTagHelperChunk.LookupText,
+ SourceLocation.Undefined,
+ TagHelperDirectiveType.RemoveTagHelper);
+
+ descriptors.Add(descriptor);
+
+ continue;
+ }
+
+ var tagHelperPrefixDirectiveChunk = chunk as TagHelperPrefixDirectiveChunk;
+ if (tagHelperPrefixDirectiveChunk != null)
+ {
+ var descriptor = new TagHelperDirectiveDescriptor(
+ tagHelperPrefixDirectiveChunk.Prefix,
+ SourceLocation.Undefined,
+ TagHelperDirectiveType.TagHelperPrefix);
+
+ descriptors.Add(descriptor);
}
}
return descriptors;
}
- private class GlobalImportAddRemoveTagHelperVisitor : TagHelperDirectiveSpanVisitor
+ private class GlobalImportTagHelperDirectiveSpanVisitor : TagHelperDirectiveSpanVisitor
{
private readonly IEnumerable _globalImportDirectiveDescriptors;
- public GlobalImportAddRemoveTagHelperVisitor(
+ public GlobalImportTagHelperDirectiveSpanVisitor(
ITagHelperDescriptorResolver descriptorResolver,
IEnumerable globalImportDirectiveDescriptors,
ParserErrorSink errorSink)
@@ -107,9 +130,43 @@ namespace Microsoft.AspNet.Mvc.Razor
IEnumerable descriptors,
ParserErrorSink errorSink)
{
- return base.GetTagHelperDescriptorResolutionContext(
- _globalImportDirectiveDescriptors.Concat(descriptors),
- errorSink);
+ var directivesToImport = MergeDirectiveDescriptors(descriptors, _globalImportDirectiveDescriptors);
+
+ return base.GetTagHelperDescriptorResolutionContext(directivesToImport, errorSink);
+ }
+
+ private static IEnumerable MergeDirectiveDescriptors(
+ IEnumerable descriptors,
+ IEnumerable inheritedDescriptors)
+ {
+ var mergedDescriptors = new List();
+ TagHelperDirectiveDescriptor prefixDirectiveDescriptor = null;
+
+ foreach (var descriptor in inheritedDescriptors)
+ {
+ if (descriptor.DirectiveType == TagHelperDirectiveType.TagHelperPrefix)
+ {
+ // Always take the latest @tagHelperPrefix descriptor. Can only have 1 per page.
+ prefixDirectiveDescriptor = descriptor;
+ }
+ else
+ {
+ mergedDescriptors.Add(descriptor);
+ }
+ }
+
+ // We need to see if the provided descriptors contain a @tagHelperPrefix directive. If so, it
+ // takes precedence and overrides any provided by the inheritedDescriptors. If not we need to add the
+ // inherited @tagHelperPrefix directive back into the merged list.
+ if (prefixDirectiveDescriptor != null &&
+ !descriptors.Any(descriptor => descriptor.DirectiveType == TagHelperDirectiveType.TagHelperPrefix))
+ {
+ mergedDescriptors.Add(prefixDirectiveDescriptor);
+ }
+
+ mergedDescriptors.AddRange(descriptors);
+
+ return mergedDescriptors;
}
}
}