diff --git a/src/Microsoft.AspNet.Razor.Runtime/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Razor.Runtime/Properties/Resources.Designer.cs
index a7f969758b..98672b3cef 100644
--- a/src/Microsoft.AspNet.Razor.Runtime/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNet.Razor.Runtime/Properties/Resources.Designer.cs
@@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Razor.Runtime
}
///
- /// Cannot resolve TagHelper containing assembly '{0}'.
+ /// Cannot resolve TagHelper containing assembly '{0}'. Error: {1}
///
internal static string TagHelperTypeResolver_CannotResolveTagHelperAssembly
{
@@ -39,11 +39,11 @@ namespace Microsoft.AspNet.Razor.Runtime
}
///
- /// Cannot resolve TagHelper containing assembly '{0}'.
+ /// Cannot resolve TagHelper containing assembly '{0}'. Error: {1}
///
- internal static string FormatTagHelperTypeResolver_CannotResolveTagHelperAssembly(object p0)
+ internal static string FormatTagHelperTypeResolver_CannotResolveTagHelperAssembly(object p0, object p1)
{
- return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperTypeResolver_CannotResolveTagHelperAssembly"), p0);
+ return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperTypeResolver_CannotResolveTagHelperAssembly"), p0, p1);
}
///
@@ -110,6 +110,22 @@ namespace Microsoft.AspNet.Razor.Runtime
return GetString("ArgumentCannotBeNullOrEmpty");
}
+ ///
+ /// Encountered an unexpected error when attempting to resolve tag helper directive '{0}' with value '{1}'. Error: {2}
+ ///
+ internal static string TagHelperDescriptorResolver_EncounteredUnexpectedError
+ {
+ get { return GetString("TagHelperDescriptorResolver_EncounteredUnexpectedError"); }
+ }
+
+ ///
+ /// Encountered an unexpected error when attempting to resolve tag helper directive '{0}' with value '{1}'. Error: {2}
+ ///
+ internal static string FormatTagHelperDescriptorResolver_EncounteredUnexpectedError(object p0, object p1, object p2)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("TagHelperDescriptorResolver_EncounteredUnexpectedError"), p0, p1, p2);
+ }
+
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
diff --git a/src/Microsoft.AspNet.Razor.Runtime/Resources.resx b/src/Microsoft.AspNet.Razor.Runtime/Resources.resx
index 46d21d10d4..d6222dec62 100644
--- a/src/Microsoft.AspNet.Razor.Runtime/Resources.resx
+++ b/src/Microsoft.AspNet.Razor.Runtime/Resources.resx
@@ -123,7 +123,7 @@
"typeName, assemblyName"
- Cannot resolve TagHelper containing assembly '{0}'.
+ Cannot resolve TagHelper containing assembly '{0}'. Error: {1}
Tag helper directive assembly name cannot be null or empty.
@@ -137,4 +137,7 @@
The value cannot be null or empty.
+
+ Encountered an unexpected error when attempting to resolve tag helper directive '{0}' with value '{1}'. Error: {2}
+
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperDescriptorResolver.cs b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperDescriptorResolver.cs
index 0793ea7b92..64ce1e5085 100644
--- a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperDescriptorResolver.cs
+++ b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperDescriptorResolver.cs
@@ -4,7 +4,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Microsoft.AspNet.Razor.Parser;
using Microsoft.AspNet.Razor.TagHelpers;
+using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
@@ -36,20 +38,42 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
foreach (var directiveDescriptor in context.DirectiveDescriptors)
{
- var lookupInfo = GetLookupInfo(directiveDescriptor);
-
- if (directiveDescriptor.DirectiveType == TagHelperDirectiveType.RemoveTagHelper)
+ try
{
- resolvedDescriptors.RemoveWhere(descriptor => MatchesLookupInfo(descriptor, lookupInfo));
+ var lookupInfo = GetLookupInfo(directiveDescriptor, context.ErrorSink);
+
+ // Could not resolve the lookup info.
+ if (lookupInfo == null)
+ {
+ return Enumerable.Empty();
+ }
+
+ if (directiveDescriptor.DirectiveType == TagHelperDirectiveType.RemoveTagHelper)
+ {
+ resolvedDescriptors.RemoveWhere(descriptor => MatchesLookupInfo(descriptor, lookupInfo));
+ }
+ else if (directiveDescriptor.DirectiveType == TagHelperDirectiveType.AddTagHelper)
+ {
+ var descriptors = ResolveDescriptorsInAssembly(lookupInfo.AssemblyName,
+ directiveDescriptor.Location,
+ context.ErrorSink);
+
+ // Only use descriptors that match our lookup info
+ descriptors = descriptors.Where(descriptor => MatchesLookupInfo(descriptor, lookupInfo));
+
+ resolvedDescriptors.UnionWith(descriptors);
+ }
}
- else if (directiveDescriptor.DirectiveType == TagHelperDirectiveType.AddTagHelper)
+ catch (Exception ex)
{
- var descriptors = ResolveDescriptorsInAssembly(lookupInfo.AssemblyName);
+ var directiveName = "@" + directiveDescriptor.DirectiveType.ToString().ToLowerInvariant();
- // Only use descriptors that match our lookup info
- descriptors = descriptors.Where(descriptor => MatchesLookupInfo(descriptor, lookupInfo));
-
- resolvedDescriptors.UnionWith(descriptors);
+ context.ErrorSink.OnError(
+ directiveDescriptor.Location,
+ Resources.FormatTagHelperDescriptorResolver_EncounteredUnexpectedError(
+ directiveName,
+ directiveDescriptor.LookupText,
+ ex.Message));
}
}
@@ -63,13 +87,18 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
///
/// The name of the assembly to resolve s from.
///
+ /// The of the directive.
+ /// Used to record errors found when resolving s
+ /// within the given .
/// s for s from the given
/// .
// This is meant to be overridden by tooling to enable assembly level caching.
- protected virtual IEnumerable ResolveDescriptorsInAssembly(string assemblyName)
+ protected virtual IEnumerable ResolveDescriptorsInAssembly(string assemblyName,
+ SourceLocation documentLocation,
+ ParserErrorSink errorSink)
{
// Resolve valid tag helper types from the assembly.
- var tagHelperTypes = _typeResolver.Resolve(assemblyName);
+ var tagHelperTypes = _typeResolver.Resolve(assemblyName, documentLocation, errorSink);
// Convert types to TagHelperDescriptors
var descriptors = tagHelperTypes.SelectMany(TagHelperDescriptorFactory.CreateDescriptors);
@@ -88,7 +117,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
string.Equals(descriptor.TypeName, lookupInfo.TypeName, StringComparison.Ordinal);
}
- private static LookupInfo GetLookupInfo(TagHelperDirectiveDescriptor directiveDescriptor)
+ private static LookupInfo GetLookupInfo(TagHelperDirectiveDescriptor directiveDescriptor,
+ ParserErrorSink errorSink)
{
var lookupText = directiveDescriptor.LookupText;
var lookupStrings = lookupText?.Split(new[] { ',' });
@@ -100,9 +130,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
lookupStrings.Any(string.IsNullOrWhiteSpace) ||
(lookupStrings.Length != 1 && lookupStrings.Length != 2))
{
- throw new ArgumentException(
- Resources.FormatTagHelperDescriptorResolver_InvalidTagHelperLookupText(lookupText),
- nameof(lookupText));
+ errorSink.OnError(
+ directiveDescriptor.Location,
+ Resources.FormatTagHelperDescriptorResolver_InvalidTagHelperLookupText(lookupText));
+
+ return null;
}
// Grab the assembly name from the lookup text strings. Due to our supported lookupText formats it will
diff --git a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperTypeResolver.cs b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperTypeResolver.cs
index 3a6897a01c..a88752ea37 100644
--- a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperTypeResolver.cs
+++ b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperTypeResolver.cs
@@ -5,6 +5,8 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
+using Microsoft.AspNet.Razor.Parser;
+using Microsoft.AspNet.Razor.Text;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
@@ -27,18 +29,43 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// all valid s.
///
/// The name of an to search.
- /// An of valid s.
- public IEnumerable Resolve(string name)
+ /// The of the associated
+ /// responsible for the current call.
+ ///
+ /// The used to record errors found when resolving
+ /// s.
+ /// An of valid s.
+ ///
+ public IEnumerable Resolve(string name,
+ SourceLocation documentLocation,
+ [NotNull] ParserErrorSink errorSink)
{
if (string.IsNullOrEmpty(name))
{
- throw new ArgumentException(
- Resources.TagHelperTypeResolver_TagHelperAssemblyNameCannotBeEmptyOrNull,
- nameof(name));
+ errorSink.OnError(documentLocation,
+ Resources.TagHelperTypeResolver_TagHelperAssemblyNameCannotBeEmptyOrNull);
+
+ return Type.EmptyTypes;
}
var assemblyName = new AssemblyName(name);
- var libraryTypes = GetLibraryDefinedTypes(assemblyName);
+
+ IEnumerable libraryTypes;
+ try
+ {
+ libraryTypes = GetLibraryDefinedTypes(assemblyName);
+ }
+ catch (Exception ex)
+ {
+ errorSink.OnError(
+ documentLocation,
+ Resources.FormatTagHelperTypeResolver_CannotResolveTagHelperAssembly(
+ assemblyName.Name,
+ ex.Message));
+
+ return Type.EmptyTypes;
+ }
+
var validTagHelpers = libraryTypes.Where(IsTagHelper);
// Convert from TypeInfo[] to Type[]
@@ -48,17 +75,9 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Internal for testing, don't want to be loading assemblies during a test.
internal virtual IEnumerable GetLibraryDefinedTypes(AssemblyName assemblyName)
{
- try
- {
- var assembly = Assembly.Load(assemblyName);
+ var assembly = Assembly.Load(assemblyName);
- return assembly.DefinedTypes;
- }
- catch (Exception ex)
- {
- throw new InvalidOperationException(
- Resources.FormatTagHelperTypeResolver_CannotResolveTagHelperAssembly(assemblyName.Name), ex);
- }
+ return assembly.ExportedTypes.Select(type => type.GetTypeInfo());
}
// Internal for testing.
diff --git a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/CSharpTagHelperCodeRenderer.cs b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/CSharpTagHelperCodeRenderer.cs
index 543f257023..a47a0a436a 100644
--- a/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/CSharpTagHelperCodeRenderer.cs
+++ b/src/Microsoft.AspNet.Razor/Generator/Compiler/CodeBuilder/CSharp/CSharpTagHelperCodeRenderer.cs
@@ -243,9 +243,8 @@ namespace Microsoft.AspNet.Razor.Generator.Compiler.CSharp
// https://github.com/aspnet/Razor/issues/129
if (!isPlainTextValue)
{
- throw new InvalidOperationException(
- RazorResources.FormatTagHelpers_AttributesThatAreNotStringsMustNotContainAtSymbols(
- attributeDescriptor.PropertyName));
+ _writer.WriteLine(";");
+ return;
}
// We aren't a bufferable attribute which means we have no Razor code in our value.
diff --git a/src/Microsoft.AspNet.Razor/Parser/RazorParser.cs b/src/Microsoft.AspNet.Razor/Parser/RazorParser.cs
index 02d2046303..4d2a21d1ec 100644
--- a/src/Microsoft.AspNet.Razor/Parser/RazorParser.cs
+++ b/src/Microsoft.AspNet.Razor/Parser/RazorParser.cs
@@ -172,7 +172,7 @@ namespace Microsoft.AspNet.Razor.Parser
if (TagHelperDescriptorResolver != null)
{
- var descriptors = GetTagHelperDescriptors(rewritingContext.SyntaxTree);
+ var descriptors = GetTagHelperDescriptors(rewritingContext.SyntaxTree, rewritingContext.ErrorSink);
var tagHelperProvider = new TagHelperDescriptorProvider(descriptors);
var tagHelperParseTreeRewriter = new TagHelperParseTreeRewriter(tagHelperProvider);
@@ -203,10 +203,15 @@ namespace Microsoft.AspNet.Razor.Parser
/// specified .
///
/// The to scan for tag helper registrations in.
- ///
- protected virtual IEnumerable GetTagHelperDescriptors([NotNull] Block documentRoot)
+ /// Used to manage s encountered during the Razor parsing
+ /// phase.
+ /// s that are applicable to the
+ ///
+ protected virtual IEnumerable GetTagHelperDescriptors([NotNull] Block documentRoot,
+ [NotNull] ParserErrorSink errorSink)
{
- var addOrRemoveTagHelperSpanVisitor = new AddOrRemoveTagHelperSpanVisitor(TagHelperDescriptorResolver);
+ var addOrRemoveTagHelperSpanVisitor =
+ new AddOrRemoveTagHelperSpanVisitor(TagHelperDescriptorResolver, errorSink);
return addOrRemoveTagHelperSpanVisitor.GetDescriptors(documentRoot);
}
diff --git a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/AddOrRemoveTagHelperSpanVisitor.cs b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/AddOrRemoveTagHelperSpanVisitor.cs
index d182f010e1..1efd57f2b8 100644
--- a/src/Microsoft.AspNet.Razor/Parser/TagHelpers/AddOrRemoveTagHelperSpanVisitor.cs
+++ b/src/Microsoft.AspNet.Razor/Parser/TagHelpers/AddOrRemoveTagHelperSpanVisitor.cs
@@ -15,12 +15,15 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
public class AddOrRemoveTagHelperSpanVisitor : ParserVisitor
{
private readonly ITagHelperDescriptorResolver _descriptorResolver;
+ private readonly ParserErrorSink _errorSink;
private List _directiveDescriptors;
- public AddOrRemoveTagHelperSpanVisitor([NotNull] ITagHelperDescriptorResolver descriptorResolver)
+ public AddOrRemoveTagHelperSpanVisitor([NotNull] ITagHelperDescriptorResolver descriptorResolver,
+ [NotNull] ParserErrorSink errorSink)
{
_descriptorResolver = descriptorResolver;
+ _errorSink = errorSink;
}
public IEnumerable GetDescriptors([NotNull] Block root)
@@ -30,7 +33,7 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
// This will recurse through the syntax tree.
VisitBlock(root);
- var resolutionContext = GetTagHelperDescriptorResolutionContext(_directiveDescriptors);
+ var resolutionContext = GetTagHelperDescriptorResolutionContext(_directiveDescriptors, _errorSink);
var descriptors = _descriptorResolver.Resolve(resolutionContext);
return descriptors;
@@ -38,9 +41,10 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
// Allows MVC a chance to override the TagHelperDescriptorResolutionContext
protected virtual TagHelperDescriptorResolutionContext GetTagHelperDescriptorResolutionContext(
- [NotNull] IEnumerable descriptors)
+ [NotNull] IEnumerable descriptors,
+ [NotNull] ParserErrorSink errorSink)
{
- return new TagHelperDescriptorResolutionContext(descriptors);
+ return new TagHelperDescriptorResolutionContext(descriptors, errorSink);
}
public override void VisitSpan(Span span)
@@ -55,7 +59,9 @@ namespace Microsoft.AspNet.Razor.Parser.TagHelpers
TagHelperDirectiveType.RemoveTagHelper :
TagHelperDirectiveType.AddTagHelper;
- var directiveDescriptor = new TagHelperDirectiveDescriptor(codeGenerator.LookupText, directive);
+ var directiveDescriptor = new TagHelperDirectiveDescriptor(codeGenerator.LookupText,
+ span.Start,
+ directive);
_directiveDescriptors.Add(directiveDescriptor);
}
diff --git a/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperDescriptorResolutionContext.cs b/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperDescriptorResolutionContext.cs
index aeb42ef875..a06d56a9f0 100644
--- a/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperDescriptorResolutionContext.cs
+++ b/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperDescriptorResolutionContext.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
+using Microsoft.AspNet.Razor.Parser;
namespace Microsoft.AspNet.Razor.TagHelpers
{
@@ -15,15 +16,23 @@ namespace Microsoft.AspNet.Razor.TagHelpers
///
/// s used to resolve
/// s.
+ /// Used to aggregate s.
public TagHelperDescriptorResolutionContext(
- [NotNull] IEnumerable directiveDescriptors)
+ [NotNull] IEnumerable directiveDescriptors,
+ [NotNull] ParserErrorSink errorSink)
{
DirectiveDescriptors = new List(directiveDescriptors);
+ ErrorSink = errorSink;
}
///
/// s used to resolve s.
///
public IList DirectiveDescriptors { get; private set; }
+
+ ///
+ /// Used to aggregate s.
+ ///
+ public ParserErrorSink ErrorSink { get; private set; }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperDirectiveDescriptor.cs b/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperDirectiveDescriptor.cs
index c16529f302..b508387b17 100644
--- a/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperDirectiveDescriptor.cs
+++ b/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperDirectiveDescriptor.cs
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using Microsoft.AspNet.Razor.Text;
+
namespace Microsoft.AspNet.Razor.TagHelpers
{
///
@@ -12,10 +14,14 @@ namespace Microsoft.AspNet.Razor.TagHelpers
/// Instantiates a new instance of .
///
/// A used to find tag helper s.
+ /// The of the directive.
/// The of this directive.
- public TagHelperDirectiveDescriptor([NotNull] string lookupText, TagHelperDirectiveType directiveType)
+ public TagHelperDirectiveDescriptor([NotNull] string lookupText,
+ SourceLocation location,
+ TagHelperDirectiveType directiveType)
{
LookupText = lookupText;
+ Location = location;
DirectiveType = directiveType;
}
@@ -28,5 +34,10 @@ namespace Microsoft.AspNet.Razor.TagHelpers
/// The of this directive.
///
public TagHelperDirectiveType DirectiveType { get; private set; }
+
+ ///
+ /// The of the directive.
+ ///
+ public SourceLocation Location { get; private set; }
}
}
\ No newline at end of file