diff --git a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperDescriptorFactory.cs b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperDescriptorFactory.cs
index 0610e40ce6..97b54512b2 100644
--- a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperDescriptorFactory.cs
+++ b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperDescriptorFactory.cs
@@ -38,23 +38,30 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
///
/// The assembly name that contains .
/// The type to create a from.
+ /// Indicates if the returned s should include
+ /// design time specific information.
+ /// The used to collect s encountered
+ /// when creating s for the given .
///
/// A collection of s that describe the given .
///
public static IEnumerable CreateDescriptors(
string assemblyName,
[NotNull] Type type,
+ bool designTime,
[NotNull] ErrorSink errorSink)
{
var typeInfo = type.GetTypeInfo();
- var attributeDescriptors = GetAttributeDescriptors(type, errorSink);
+ var attributeDescriptors = GetAttributeDescriptors(type, designTime, errorSink);
var targetElementAttributes = GetValidTargetElementAttributes(typeInfo, errorSink);
+
var tagHelperDescriptors =
BuildTagHelperDescriptors(
typeInfo,
assemblyName,
attributeDescriptors,
- targetElementAttributes);
+ targetElementAttributes,
+ designTime);
return tagHelperDescriptors.Distinct(TagHelperDescriptorComparer.Default);
}
@@ -72,8 +79,18 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
TypeInfo typeInfo,
string assemblyName,
IEnumerable attributeDescriptors,
- IEnumerable targetElementAttributes)
+ IEnumerable targetElementAttributes,
+ bool designTime)
{
+ TagHelperUsageDescriptor typeUsageDescriptor = null;
+
+#if !DNXCORE50
+ if (designTime)
+ {
+ typeUsageDescriptor = TagHelperUsageDescriptorFactory.CreateDescriptor(typeInfo.GetType());
+ }
+#endif
+
var typeName = typeInfo.FullName;
// If there isn't an attribute specifying the tag name derive it from the name
@@ -93,19 +110,27 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
typeName,
assemblyName,
attributeDescriptors,
- requiredAttributes: Enumerable.Empty())
+ requiredAttributes: Enumerable.Empty(),
+ usageDescriptor: typeUsageDescriptor)
};
}
return targetElementAttributes.Select(
- attribute => BuildTagHelperDescriptor(typeName, assemblyName, attributeDescriptors, attribute));
+ attribute =>
+ BuildTagHelperDescriptor(
+ typeName,
+ assemblyName,
+ attributeDescriptors,
+ attribute,
+ typeUsageDescriptor));
}
private static TagHelperDescriptor BuildTagHelperDescriptor(
string typeName,
string assemblyName,
IEnumerable attributeDescriptors,
- TargetElementAttribute targetElementAttribute)
+ TargetElementAttribute targetElementAttribute,
+ TagHelperUsageDescriptor usageDescriptor)
{
var requiredAttributes = GetCommaSeparatedValues(targetElementAttribute.Attributes);
@@ -114,7 +139,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
typeName,
assemblyName,
attributeDescriptors,
- requiredAttributes);
+ requiredAttributes,
+ usageDescriptor);
}
private static TagHelperDescriptor BuildTagHelperDescriptor(
@@ -122,7 +148,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
string typeName,
string assemblyName,
IEnumerable attributeDescriptors,
- IEnumerable requiredAttributes)
+ IEnumerable requiredAttributes,
+ TagHelperUsageDescriptor usageDescriptor)
{
return new TagHelperDescriptor(
prefix: string.Empty,
@@ -130,7 +157,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
typeName: typeName,
assemblyName: assemblyName,
attributes: attributeDescriptors,
- requiredAttributes: requiredAttributes);
+ requiredAttributes: requiredAttributes,
+ usageDescriptor: usageDescriptor);
}
///
@@ -225,6 +253,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
private static IEnumerable GetAttributeDescriptors(
Type type,
+ bool designTime,
ErrorSink errorSink)
{
var accessibleProperties = type.GetRuntimeProperties().Where(IsAccessibleProperty);
@@ -236,7 +265,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
foreach (var property in accessibleProperties)
{
var attributeNameAttribute = property.GetCustomAttribute(inherit: false);
- var descriptor = ToAttributeDescriptor(property, attributeNameAttribute);
+ var descriptor = ToAttributeDescriptor(property, attributeNameAttribute, designTime);
if (ValidateTagHelperAttributeDescriptor(descriptor, type, errorSink))
{
bool isInvalid;
@@ -246,6 +275,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
parentType: type,
errorSink: errorSink,
defaultPrefix: descriptor.Name + "-",
+ designTime: designTime,
isInvalid: out isInvalid);
if (indexerDescriptor != null &&
@@ -358,17 +388,19 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
private static TagHelperAttributeDescriptor ToAttributeDescriptor(
PropertyInfo property,
- HtmlAttributeNameAttribute attributeNameAttribute)
+ HtmlAttributeNameAttribute attributeNameAttribute,
+ bool designTime)
{
var attributeName = attributeNameAttribute != null ?
attributeNameAttribute.Name :
ToHtmlCase(property.Name);
- return new TagHelperAttributeDescriptor(
+ return ToAttributeDescriptor(
+ property,
attributeName,
- property.Name,
property.PropertyType.FullName,
- isIndexer: false);
+ isIndexer: false,
+ designTime: designTime);
}
private static TagHelperAttributeDescriptor ToIndexerAttributeDescriptor(
@@ -377,6 +409,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Type parentType,
ErrorSink errorSink,
string defaultPrefix,
+ bool designTime,
out bool isInvalid)
{
isInvalid = false;
@@ -414,11 +447,36 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
return null;
}
- return new TagHelperAttributeDescriptor(
- name: prefix,
- propertyName: property.Name,
+ return ToAttributeDescriptor(
+ property,
+ attributeName: prefix,
typeName: dictionaryTypeArguments[1].FullName,
- isIndexer: true);
+ isIndexer: true,
+ designTime: designTime);
+ }
+
+ private static TagHelperAttributeDescriptor ToAttributeDescriptor(
+ PropertyInfo property,
+ string attributeName,
+ string typeName,
+ bool isIndexer,
+ bool designTime)
+ {
+ TagHelperUsageDescriptor propertyUsageDescriptor = null;
+
+#if !DNXCORE50
+ if (designTime)
+ {
+ propertyUsageDescriptor = TagHelperUsageDescriptorFactory.CreateDescriptor(property);
+ }
+#endif
+
+ return new TagHelperAttributeDescriptor(
+ attributeName,
+ property.Name,
+ typeName,
+ isIndexer,
+ propertyUsageDescriptor);
}
private static bool IsAccessibleProperty(PropertyInfo property)
diff --git a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperDescriptorResolver.cs b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperDescriptorResolver.cs
index da7fc974a3..fa1835b421 100644
--- a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperDescriptorResolver.cs
+++ b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperDescriptorResolver.cs
@@ -26,14 +26,16 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
};
private readonly TagHelperTypeResolver _typeResolver;
+ private readonly bool _designTime;
///
/// Instantiates a new instance of the class.
///
- public TagHelperDescriptorResolver()
- : this(new TagHelperTypeResolver())
+ /// Indicates whether resolved s should include
+ /// design time specific information.
+ public TagHelperDescriptorResolver(bool designTime)
+ : this(new TagHelperTypeResolver(), designTime)
{
-
}
///
@@ -41,9 +43,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// specified .
///
/// The .
- public TagHelperDescriptorResolver(TagHelperTypeResolver typeResolver)
+ /// Indicates whether resolved s should include
+ /// design time specific information.
+ public TagHelperDescriptorResolver(TagHelperTypeResolver typeResolver, bool designTime)
{
_typeResolver = typeResolver;
+ _designTime = designTime;
}
///
@@ -113,7 +118,7 @@ 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
+ /// Used to record errors found when resolving s
/// within the given .
/// s for s from the given
/// .
@@ -128,7 +133,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Convert types to TagHelperDescriptors
var descriptors = tagHelperTypes.SelectMany(
- type => TagHelperDescriptorFactory.CreateDescriptors(assemblyName, type, errorSink));
+ type => TagHelperDescriptorFactory.CreateDescriptors(assemblyName, type, _designTime, errorSink));
return descriptors;
}
@@ -148,7 +153,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
descriptor.TypeName,
descriptor.AssemblyName,
descriptor.Attributes,
- descriptor.RequiredAttributes));
+ descriptor.RequiredAttributes,
+ descriptor.UsageDescriptor));
}
return descriptors;
@@ -222,7 +228,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// We need to escape the TypePattern so we can choose to only allow specific regex.
var escaped = Regex.Escape(lookupInfo.TypePattern);
- // We surround the escaped with ^ and $ in order ot ensure a regex match matches the entire
+ // We surround the escaped with ^ and $ in order ot ensure a regex match matches the entire
// string. We also replace any '*' or '?' characters with regex to match appropriate content.
// '*' matches 0 or more characters lazily and '?' matches 1 character.
var pattern = "^" + escaped.Replace(@"\?", ".").Replace(@"\*", ".*?") + "$";
diff --git a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperUsageDescriptorFactory.cs b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperUsageDescriptorFactory.cs
new file mode 100644
index 0000000000..ee7a191894
--- /dev/null
+++ b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperUsageDescriptorFactory.cs
@@ -0,0 +1,162 @@
+// 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.
+
+#if !DNXCORE50 // Cannot accurately resolve the location of the documentation XML file in coreclr.
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using Microsoft.AspNet.Razor.TagHelpers;
+using Microsoft.Framework.Internal;
+
+namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
+{
+ ///
+ /// Factory for providing s from s and
+ /// s.
+ ///
+ public static class TagHelperUsageDescriptorFactory
+ {
+ ///
+ /// Creates a from the given .
+ ///
+ /// The to create a from.
+ /// A that describes the summary and remarks XML documentation
+ /// for the given .
+ public static TagHelperUsageDescriptor CreateDescriptor([NotNull] Type type)
+ {
+ var id = XmlDocumentationProvider.GetId(type);
+
+ return CreateDescriptorCore(type.Assembly, id);
+ }
+
+ ///
+ /// Creates a from the given .
+ ///
+ /// The to create a
+ /// from.
+ /// A that describes the summary and remarks XML documentation
+ /// for the given .
+ public static TagHelperUsageDescriptor CreateDescriptor([NotNull] PropertyInfo propertyInfo)
+ {
+ var id = XmlDocumentationProvider.GetId(propertyInfo);
+ var declaringAssembly = propertyInfo.DeclaringType.Assembly;
+
+ return CreateDescriptorCore(declaringAssembly, id);
+ }
+
+ private static TagHelperUsageDescriptor CreateDescriptorCore(Assembly assembly, string id)
+ {
+ var assemblyLocation = assembly.Location;
+
+ if (string.IsNullOrEmpty(assemblyLocation) && !string.IsNullOrEmpty(assembly.CodeBase))
+ {
+ var uri = new UriBuilder(assembly.CodeBase);
+
+ // Normalize the path to a UNC path. This will remove things like file:// from start of the uri.Path.
+ assemblyLocation = Uri.UnescapeDataString(uri.Path);
+ }
+
+ // Couldn't resolve a valid assemblyLocation.
+ if (string.IsNullOrEmpty(assemblyLocation))
+ {
+ return null;
+ }
+
+ var xmlDocumentationFile = GetXmlDocumentationFile(assembly, assemblyLocation);
+
+ // Only want to process the file if it exists.
+ if (xmlDocumentationFile != null)
+ {
+ var documentationProvider = new XmlDocumentationProvider(xmlDocumentationFile.FullName);
+
+ var summary = documentationProvider.GetSummary(id);
+ var remarks = documentationProvider.GetRemarks(id);
+
+ if (!string.IsNullOrEmpty(summary) || !string.IsNullOrEmpty(remarks))
+ {
+ return new TagHelperUsageDescriptor(summary, remarks);
+ }
+ }
+
+ return null;
+ }
+
+ private static FileInfo GetXmlDocumentationFile(Assembly assembly, string assemblyLocation)
+ {
+ try
+ {
+ var assemblyDirectory = Path.GetDirectoryName(assemblyLocation);
+ var assemblyName = Path.GetFileName(assemblyLocation);
+ var assemblyXmlDocumentationName = Path.ChangeExtension(assemblyName, ".xml");
+
+ // Check for a localized XML file for the current culture.
+ var xmlDocumentationFile = GetLocalizedXmlDocumentationFile(
+ CultureInfo.CurrentCulture,
+ assemblyDirectory,
+ assemblyXmlDocumentationName);
+
+ if (xmlDocumentationFile == null)
+ {
+ // Check for a culture-neutral XML file next to the assembly
+ xmlDocumentationFile = new FileInfo(
+ Path.Combine(assemblyDirectory, assemblyXmlDocumentationName));
+
+ if (!xmlDocumentationFile.Exists)
+ {
+ xmlDocumentationFile = null;
+ }
+ }
+
+ return xmlDocumentationFile;
+ }
+ catch (ArgumentException)
+ {
+ // Could not resolve XML file.
+ return null;
+ }
+ }
+
+ private static IEnumerable ExpandPaths(
+ CultureInfo culture,
+ string assemblyDirectory,
+ string assemblyXmlDocumentationName)
+ {
+ // Following the fall-back process defined by:
+ // https://msdn.microsoft.com/en-us/library/sb6a8618.aspx#cpconpackagingdeployingresourcesanchor1
+ do
+ {
+ var cultureName = culture.Name;
+ var cultureSpecificFileName =
+ Path.ChangeExtension(assemblyXmlDocumentationName, cultureName + ".xml");
+
+ // Look for a culture specific XML file next to the assembly.
+ yield return Path.Combine(assemblyDirectory, cultureSpecificFileName);
+
+ // Look for an XML file with the same name as the assembly in a culture specific directory.
+ yield return Path.Combine(assemblyDirectory, cultureName, assemblyXmlDocumentationName);
+
+ // Look for a culture specific XML file in a culture specific directory.
+ yield return Path.Combine(assemblyDirectory, cultureName, cultureSpecificFileName);
+
+ culture = culture.Parent;
+ } while (culture != null && culture != CultureInfo.InvariantCulture);
+ }
+
+ private static FileInfo GetLocalizedXmlDocumentationFile(
+ CultureInfo culture,
+ string assemblyDirectory,
+ string assemblyXmlDocumentationName)
+ {
+ var localizedXmlPaths = ExpandPaths(culture, assemblyDirectory, assemblyXmlDocumentationName);
+ var xmlDocumentationFile = localizedXmlPaths
+ .Select(path => new FileInfo(path))
+ .FirstOrDefault(file => file.Exists);
+
+ return xmlDocumentationFile;
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Razor.Runtime/XMLDocumentationProvider.cs b/src/Microsoft.AspNet.Razor.Runtime/XMLDocumentationProvider.cs
new file mode 100644
index 0000000000..7132cc1f80
--- /dev/null
+++ b/src/Microsoft.AspNet.Razor.Runtime/XMLDocumentationProvider.cs
@@ -0,0 +1,120 @@
+// 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.
+
+#if !DNXCORE50
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Xml.Linq;
+using Microsoft.Framework.Internal;
+
+namespace Microsoft.AspNet.Razor.Runtime
+{
+ ///
+ /// Extracts summary and remarks XML documentation from an XML documentation file.
+ ///
+ public class XmlDocumentationProvider
+ {
+ private readonly IEnumerable _members;
+
+ ///
+ /// Instantiates a new instance of the .
+ ///
+ /// Path to the XML documentation file to read.
+ public XmlDocumentationProvider(string xmlFileLocation)
+ {
+ // XML file processing is defined by: https://msdn.microsoft.com/en-us/library/fsbx0t7x.aspx
+ var xmlDocumentation = XDocument.Load(xmlFileLocation);
+ var documentationRootMembers = xmlDocumentation.Root.Element("members");
+ _members = documentationRootMembers.Elements("member");
+ }
+
+ ///
+ /// Retrieves the <summary> documentation for the given .
+ ///
+ /// The id to lookup.
+ /// <summary> documentation for the given .
+ public string GetSummary(string id)
+ {
+ var associatedMemeber = GetMember(id);
+ var summaryElement = associatedMemeber?.Element("summary");
+
+ if (summaryElement != null)
+ {
+ var summaryValue = GetElementValue(summaryElement);
+
+ return summaryValue;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Retrieves the <remarks> documentation for the given .
+ ///
+ /// The id to lookup.
+ /// <remarks> documentation for the given .
+ public string GetRemarks(string id)
+ {
+ var associatedMemeber = GetMember(id);
+ var remarksElement = associatedMemeber?.Element("remarks");
+
+ if (remarksElement != null)
+ {
+ var remarksValue = GetElementValue(remarksElement);
+
+ return remarksValue;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Generates the identifier for the given .
+ ///
+ /// The to get the identifier for.
+ /// The identifier for the given .
+ public static string GetId([NotNull] Type type)
+ {
+ return $"T:{type.FullName}";
+ }
+
+ ///
+ /// Generates the identifier for the given .
+ ///
+ /// The to get the identifier for.
+ /// The identifier for the given .
+ public static string GetId([NotNull] PropertyInfo propertyInfo)
+ {
+ var declaringTypeInfo = propertyInfo.DeclaringType;
+ return $"P:{declaringTypeInfo.FullName}.{propertyInfo.Name}";
+ }
+
+ private XElement GetMember(string id)
+ {
+ var associatedMemeber = _members
+ .FirstOrDefault(element =>
+ string.Equals(element.Attribute("name").Value, id, StringComparison.Ordinal));
+
+ return associatedMemeber;
+ }
+
+ private static string GetElementValue(XElement element)
+ {
+ var stringBuilder = new StringBuilder();
+ var node = element.FirstNode;
+
+ while (node != null)
+ {
+ stringBuilder.Append(node.ToString(SaveOptions.DisableFormatting));
+
+ node = node.NextNode;
+ }
+
+ return stringBuilder.ToString().Trim();
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Razor.Runtime/project.json b/src/Microsoft.AspNet.Razor.Runtime/project.json
index e37620525c..f596d4f4c9 100644
--- a/src/Microsoft.AspNet.Razor.Runtime/project.json
+++ b/src/Microsoft.AspNet.Razor.Runtime/project.json
@@ -9,8 +9,18 @@
"Microsoft.Framework.NotNullAttribute.Sources": { "type": "build", "version": "1.0.0-*" }
},
"frameworks": {
- "net45": { },
- "dnx451": { },
+ "net45": {
+ "frameworkAssemblies": {
+ "System.Xml": "4.0.0.0",
+ "System.Xml.Linq": "4.0.0.0"
+ }
+ },
+ "dnx451": {
+ "frameworkAssemblies": {
+ "System.Xml": "4.0.0.0",
+ "System.Xml.Linq": "4.0.0.0"
+ }
+ },
"dnxcore50": {
"dependencies": {
"System.Reflection.Extensions": "4.0.0-beta-*",
diff --git a/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperAttributeDescriptor.cs b/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperAttributeDescriptor.cs
index a4c370ae7b..b994136e1d 100644
--- a/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperAttributeDescriptor.cs
+++ b/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperAttributeDescriptor.cs
@@ -19,7 +19,8 @@ namespace Microsoft.AspNet.Razor.TagHelpers
propertyInfo.Name,
propertyInfo.PropertyType.FullName,
isIndexer: false,
- isStringProperty: propertyInfo.PropertyType == typeof(string))
+ isStringProperty: propertyInfo.PropertyType == typeof(string),
+ usageDescriptor: null)
{
}
@@ -39,6 +40,8 @@ namespace Microsoft.AspNet.Razor.TagHelpers
/// If true this is used for dictionary indexer assignments.
/// Otherwise this is used for property assignment.
///
+ /// The that contains information about
+ /// use of this attribute.
///
/// HTML attribute names are matched case-insensitively, regardless of .
///
@@ -46,13 +49,15 @@ namespace Microsoft.AspNet.Razor.TagHelpers
[NotNull] string name,
[NotNull] string propertyName,
[NotNull] string typeName,
- bool isIndexer)
+ bool isIndexer,
+ TagHelperUsageDescriptor usageDescriptor)
: this(
name,
propertyName,
typeName,
isIndexer,
- isStringProperty: string.Equals(typeName, typeof(string).FullName, StringComparison.Ordinal))
+ isStringProperty: string.Equals(typeName, typeof(string).FullName, StringComparison.Ordinal),
+ usageDescriptor: usageDescriptor)
{
}
@@ -62,13 +67,15 @@ namespace Microsoft.AspNet.Razor.TagHelpers
[NotNull] string propertyName,
[NotNull] string typeName,
bool isIndexer,
- bool isStringProperty)
+ bool isStringProperty,
+ TagHelperUsageDescriptor usageDescriptor)
{
Name = name;
PropertyName = propertyName;
TypeName = typeName;
IsIndexer = isIndexer;
IsStringProperty = isStringProperty;
+ UsageDescriptor = usageDescriptor;
}
///
@@ -111,6 +118,11 @@ namespace Microsoft.AspNet.Razor.TagHelpers
///
public string TypeName { get; }
+ ///
+ /// The that contains information about use of this attribute.
+ ///
+ public TagHelperUsageDescriptor UsageDescriptor { get; }
+
///
/// Determines whether HTML attribute matches this
/// .
diff --git a/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperAttributeDescriptorComparer.cs b/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperAttributeDescriptorComparer.cs
deleted file mode 100644
index c118af1406..0000000000
--- a/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperAttributeDescriptorComparer.cs
+++ /dev/null
@@ -1,68 +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;
-using System.Collections.Generic;
-using Microsoft.Framework.Internal;
-using Microsoft.Internal.Web.Utils;
-
-namespace Microsoft.AspNet.Razor.TagHelpers
-{
- ///
- /// An used to check equality between
- /// two s.
- ///
- public class TagHelperAttributeDescriptorComparer : IEqualityComparer
- {
- ///
- /// A default instance of the .
- ///
- public static readonly TagHelperAttributeDescriptorComparer Default =
- new TagHelperAttributeDescriptorComparer();
-
- ///
- /// Initializes a new instance.
- ///
- protected TagHelperAttributeDescriptorComparer()
- {
- }
-
- ///
- ///
- /// Determines equality based on ,
- /// , ,
- /// and . Ignores
- /// because it can be inferred directly from
- /// .
- ///
- public virtual bool Equals(TagHelperAttributeDescriptor descriptorX, TagHelperAttributeDescriptor descriptorY)
- {
- if (descriptorX == descriptorY)
- {
- return true;
- }
-
- // Check Name and TypeName though each property in a particular tag helper has at most two
- // TagHelperAttributeDescriptors (one for the indexer and one not). May be comparing attributes between
- // tag helpers and should be as specific as we can.
- return descriptorX != null &&
- descriptorX.IsIndexer == descriptorY.IsIndexer &&
- string.Equals(descriptorX.Name, descriptorY.Name, StringComparison.OrdinalIgnoreCase) &&
- string.Equals(descriptorX.PropertyName, descriptorY.PropertyName, StringComparison.Ordinal) &&
- string.Equals(descriptorX.TypeName, descriptorY.TypeName, StringComparison.Ordinal);
- }
-
- ///
- public virtual int GetHashCode([NotNull] TagHelperAttributeDescriptor descriptor)
- {
- // Rarely if ever hash TagHelperAttributeDescriptor. If we do, include the Name and TypeName since context
- // information is not available in the hash.
- return HashCodeCombiner.Start()
- .Add(descriptor.IsIndexer)
- .Add(descriptor.Name, StringComparer.OrdinalIgnoreCase)
- .Add(descriptor.PropertyName, StringComparer.Ordinal)
- .Add(descriptor.TypeName, StringComparer.Ordinal)
- .CombinedHash;
- }
- }
-}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperDescriptor.cs b/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperDescriptor.cs
index 80d07b2028..cc0e4c6808 100644
--- a/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperDescriptor.cs
+++ b/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperDescriptor.cs
@@ -59,7 +59,8 @@ namespace Microsoft.AspNet.Razor.TagHelpers
typeName: typeName,
assemblyName: assemblyName,
attributes: attributes,
- requiredAttributes: requiredAttributes)
+ requiredAttributes: requiredAttributes,
+ usageDescriptor: null)
{
}
@@ -81,13 +82,16 @@ namespace Microsoft.AspNet.Razor.TagHelpers
///
/// The attribute names required for the tag helper to target the HTML tag.
///
+ /// The that contains information about
+ /// how to use the tag helper at design time.
public TagHelperDescriptor(
string prefix,
[NotNull] string tagName,
[NotNull] string typeName,
[NotNull] string assemblyName,
[NotNull] IEnumerable attributes,
- [NotNull] IEnumerable requiredAttributes)
+ [NotNull] IEnumerable requiredAttributes,
+ TagHelperUsageDescriptor usageDescriptor)
{
Prefix = prefix ?? string.Empty;
TagName = tagName;
@@ -96,39 +100,40 @@ namespace Microsoft.AspNet.Razor.TagHelpers
AssemblyName = assemblyName;
Attributes = new List(attributes);
RequiredAttributes = new List(requiredAttributes);
+ UsageDescriptor = usageDescriptor;
}
///
/// Text used as a required prefix when matching HTML start and end tags in the Razor source to available
/// tag helpers.
///
- public string Prefix { get; private set; }
+ public string Prefix { get; }
///
/// The tag name that the tag helper should target.
///
- public string TagName { get; private set; }
+ public string TagName { get; }
///
/// The full tag name that is required for the tag helper to target an HTML element.
///
/// This is equivalent to and concatenated.
- public string FullTagName { get; private set; }
+ public string FullTagName { get; }
///
/// The full name of the tag helper class.
///
- public string TypeName { get; private set; }
+ public string TypeName { get; }
///
/// The name of the assembly containing the tag helper class.
///
- public string AssemblyName { get; private set; }
+ public string AssemblyName { get; }
///
/// The list of attributes the tag helper expects.
///
- public IReadOnlyList Attributes { get; private set; }
+ public IReadOnlyList Attributes { get; }
///
/// The list of required attribute names the tag helper expects to target an element.
@@ -136,6 +141,12 @@ namespace Microsoft.AspNet.Razor.TagHelpers
///
/// * at the end of an attribute name acts as a prefix match.
///
- public IReadOnlyList RequiredAttributes { get; private set; }
+ public IReadOnlyList RequiredAttributes { get; }
+
+ ///
+ /// The that contains information about how to use the tag helper at
+ /// design time.
+ ///
+ public TagHelperUsageDescriptor UsageDescriptor { get; }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperDescriptorComparer.cs b/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperDescriptorComparer.cs
index 8eb961b0c4..2ea1b9dbee 100644
--- a/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperDescriptorComparer.cs
+++ b/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperDescriptorComparer.cs
@@ -31,7 +31,9 @@ namespace Microsoft.AspNet.Razor.TagHelpers
///
/// Determines equality based on ,
/// , ,
- /// and .
+ /// and . Ignores
+ /// because it can be inferred directly from
+ /// and .
///
public virtual bool Equals(TagHelperDescriptor descriptorX, TagHelperDescriptor descriptorY)
{
diff --git a/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperUsageDescriptor.cs b/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperUsageDescriptor.cs
new file mode 100644
index 0000000000..5a3918f4e9
--- /dev/null
+++ b/src/Microsoft.AspNet.Razor/TagHelpers/TagHelperUsageDescriptor.cs
@@ -0,0 +1,32 @@
+// 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.
+
+namespace Microsoft.AspNet.Razor.TagHelpers
+{
+ ///
+ /// A metadata class containing information about tag helper use.
+ ///
+ public class TagHelperUsageDescriptor
+ {
+ ///
+ /// Instantiates a new instance of .
+ ///
+ /// A summary on how to use a tag helper.
+ /// Remarks on how to use a tag helper.
+ public TagHelperUsageDescriptor(string summary, string remarks)
+ {
+ Summary = summary;
+ Remarks = remarks;
+ }
+
+ ///
+ /// A summary of how to use a tag helper.
+ ///
+ public string Summary { get; }
+
+ ///
+ /// Remarks about how to use a tag helper.
+ ///
+ public string Remarks { get; }
+ }
+}
\ No newline at end of file