Create an abstraction model for TypeInfo for tag helper discovery.
This commit is contained in:
parent
08c8f9f7ba
commit
231e8a9cf4
|
|
@ -0,0 +1,30 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Metadata common to types and properties.
|
||||
/// </summary>
|
||||
public interface IMemberInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection of custom <see cref="Attribute"/>s of type <typeparamref name="TAttribute"/> applied
|
||||
/// to this instance of <see cref="IMemberInfo"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TAttribute">The type of <see cref="Attribute"/> to search for.</typeparam>
|
||||
/// <returns>A sequence of custom <see cref="Attribute"/>s of type
|
||||
/// <typeparamref name="TAttribute"/>.</returns>
|
||||
/// <remarks>Result not include inherited <see cref="Attribute"/>s.</remarks>
|
||||
IEnumerable<TAttribute> GetCustomAttributes<TAttribute>()
|
||||
where TAttribute : Attribute;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// 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.Runtime.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains property metadata.
|
||||
/// </summary>
|
||||
public interface IPropertyInfo : IMemberInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this property has a public getter.
|
||||
/// </summary>
|
||||
bool HasPublicGetter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this property has a public setter.
|
||||
/// </summary>
|
||||
bool HasPublicSetter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ITypeInfo"/> of the property.
|
||||
/// </summary>
|
||||
ITypeInfo PropertyType { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
// 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.Razor.Runtime.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains type metadata.
|
||||
/// </summary>
|
||||
public interface ITypeInfo : IMemberInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Fully qualified name of the type.
|
||||
/// </summary>
|
||||
string FullName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets <see cref="IPropertyInfo"/>s for all properties of the current type excluding indexers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Indexers in this context refer to the CLR notion of an indexer (<c>this [string name]</c>
|
||||
/// and does not overlap with the semantics of
|
||||
/// <see cref="Razor.TagHelpers.TagHelperAttributeDescriptor.IsIndexer"/>.
|
||||
/// </remarks>
|
||||
IEnumerable<IPropertyInfo> Properties { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the type is public.
|
||||
/// </summary>
|
||||
bool IsPublic { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the type is abstract or an interface.
|
||||
/// </summary>
|
||||
bool IsAbstract { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the type is generic.
|
||||
/// </summary>
|
||||
bool IsGenericType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the type implements the <see cref="ITagHelper"/> interface.
|
||||
/// </summary>
|
||||
bool IsTagHelper { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the full names of the parameter types if the type implements
|
||||
/// <see cref="IDictionary{TKey, TValue}"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The full type names (<seealso cref="System.Type.FullName"/>) of <c>TKey</c> and <c>TValue</c>
|
||||
/// parameters if the type implements <see cref="IDictionary{TKey, TValue}"/>, otherwise <c>null</c>.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// For open generic types, full type names for generic type parameters is <c>null</c>.
|
||||
/// </remarks>
|
||||
string[] GetGenericDictionaryParameterNames();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// 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 System.Reflection;
|
||||
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="IPropertyInfo"/> adapter for <see cref="PropertyInfo"/> instances.
|
||||
/// </summary>
|
||||
public class RuntimePropertyInfo : IPropertyInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="RuntimePropertyInfo"/>.
|
||||
/// </summary>
|
||||
/// <param name="propertyInfo">The <see cref="PropertyInfo"/> instance to adapt.</param>
|
||||
public RuntimePropertyInfo([NotNull] PropertyInfo propertyInfo)
|
||||
{
|
||||
Property = propertyInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="PropertyInfo"/> instance.
|
||||
/// </summary>
|
||||
public PropertyInfo Property { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasPublicGetter => Property.GetMethod != null && Property.GetMethod.IsPublic;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasPublicSetter => Property.SetMethod != null && Property.SetMethod.IsPublic;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Property.Name;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ITypeInfo PropertyType => new RuntimeTypeInfo(Property.PropertyType.GetTypeInfo());
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<TAttribute> GetCustomAttributes<TAttribute>() where TAttribute : Attribute
|
||||
=> Property.GetCustomAttributes<TAttribute>(inherit: false);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString() =>
|
||||
Property.ToString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
// 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 System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="ITypeInfo"/> adapter for <see cref="System.Reflection.TypeInfo"/> instances.
|
||||
/// </summary>
|
||||
public class RuntimeTypeInfo : ITypeInfo
|
||||
{
|
||||
private static readonly TypeInfo TagHelperTypeInfo = typeof(ITagHelper).GetTypeInfo();
|
||||
private IEnumerable<IPropertyInfo> _properties;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="RuntimeTypeInfo"/>
|
||||
/// </summary>
|
||||
/// <param name="propertyInfo">The <see cref="System.Reflection.TypeInfo"/> instance to adapt.</param>
|
||||
public RuntimeTypeInfo([NotNull] TypeInfo typeInfo)
|
||||
{
|
||||
TypeInfo = typeInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="System.Reflection.TypeInfo"/> instance.
|
||||
/// </summary>
|
||||
public TypeInfo TypeInfo { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => TypeInfo.Name;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string FullName => TypeInfo.FullName;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsAbstract => TypeInfo.IsAbstract;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsGenericType => TypeInfo.IsGenericType;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsPublic => TypeInfo.IsPublic;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<IPropertyInfo> Properties
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_properties == null)
|
||||
{
|
||||
_properties = TypeInfo
|
||||
.AsType()
|
||||
.GetRuntimeProperties()
|
||||
.Where(property => property.GetIndexParameters().Length == 0)
|
||||
.Select(property => new RuntimePropertyInfo(property));
|
||||
}
|
||||
|
||||
return _properties;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsTagHelper => TagHelperTypeInfo.IsAssignableFrom(TypeInfo);
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<TAttribute> GetCustomAttributes<TAttribute>() where TAttribute : Attribute =>
|
||||
TypeInfo.GetCustomAttributes<TAttribute>(inherit: false);
|
||||
|
||||
/// <inheritdoc />
|
||||
public string[] GetGenericDictionaryParameterNames()
|
||||
{
|
||||
return ClosedGenericMatcher.ExtractGenericInterface(
|
||||
TypeInfo.AsType(),
|
||||
typeof(IDictionary<,>))
|
||||
?.GenericTypeArguments
|
||||
.Select(type => type.FullName)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString() => TypeInfo.ToString();
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNet.Razor.TagHelpers;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
|
@ -13,7 +12,7 @@ using Microsoft.Framework.Internal;
|
|||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Factory for <see cref="TagHelperDescriptor"/>s from <see cref="Type"/>s.
|
||||
/// Factory for <see cref="TagHelperDescriptor"/>s from <see cref="ITypeInfo"/>s.
|
||||
/// </summary>
|
||||
public static class TagHelperDescriptorFactory
|
||||
{
|
||||
|
|
@ -35,31 +34,30 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
new[] { '@', '!', '<', '/', '?', '[', '>', ']', '=', '"', '\'', '*' });
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="TagHelperDescriptor"/> from the given <paramref name="type"/>.
|
||||
/// Creates a <see cref="TagHelperDescriptor"/> from the given <paramref name="typeInfo"/>.
|
||||
/// </summary>
|
||||
/// <param name="assemblyName">The assembly name that contains <paramref name="type"/>.</param>
|
||||
/// <param name="type">The type to create a <see cref="TagHelperDescriptor"/> from.</param>
|
||||
/// <param name="typeInfo">The <see cref="ITypeInfo"/> to create a <see cref="TagHelperDescriptor"/> from.
|
||||
/// </param>
|
||||
/// <param name="designTime">Indicates if the returned <see cref="TagHelperDescriptor"/>s should include
|
||||
/// design time specific information.</param>
|
||||
/// <param name="errorSink">The <see cref="ErrorSink"/> used to collect <see cref="RazorError"/>s encountered
|
||||
/// when creating <see cref="TagHelperDescriptor"/>s for the given <paramref name="type"/>.</param>
|
||||
/// when creating <see cref="TagHelperDescriptor"/>s for the given <paramref name="typeInfo"/>.</param>
|
||||
/// <returns>
|
||||
/// A collection of <see cref="TagHelperDescriptor"/>s that describe the given <paramref name="type"/>.
|
||||
/// A collection of <see cref="TagHelperDescriptor"/>s that describe the given <paramref name="typeInfo"/>.
|
||||
/// </returns>
|
||||
public static IEnumerable<TagHelperDescriptor> CreateDescriptors(
|
||||
string assemblyName,
|
||||
[NotNull] Type type,
|
||||
[NotNull] ITypeInfo typeInfo,
|
||||
bool designTime,
|
||||
[NotNull] ErrorSink errorSink)
|
||||
{
|
||||
var typeInfo = type.GetTypeInfo();
|
||||
|
||||
if (ShouldSkipDescriptorCreation(designTime, typeInfo))
|
||||
{
|
||||
return Enumerable.Empty<TagHelperDescriptor>();
|
||||
}
|
||||
|
||||
var attributeDescriptors = GetAttributeDescriptors(type, designTime, errorSink);
|
||||
var attributeDescriptors = GetAttributeDescriptors(typeInfo, designTime, errorSink);
|
||||
var targetElementAttributes = GetValidTargetElementAttributes(typeInfo, errorSink);
|
||||
var allowedChildren = GetAllowedChildren(typeInfo, errorSink);
|
||||
|
||||
|
|
@ -76,16 +74,16 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
}
|
||||
|
||||
private static IEnumerable<TargetElementAttribute> GetValidTargetElementAttributes(
|
||||
TypeInfo typeInfo,
|
||||
ITypeInfo typeInfo,
|
||||
ErrorSink errorSink)
|
||||
{
|
||||
var targetElementAttributes = typeInfo.GetCustomAttributes<TargetElementAttribute>(inherit: false);
|
||||
var targetElementAttributes = typeInfo.GetCustomAttributes<TargetElementAttribute>();
|
||||
|
||||
return targetElementAttributes.Where(attribute => ValidTargetElementAttributeNames(attribute, errorSink));
|
||||
}
|
||||
|
||||
private static IEnumerable<TagHelperDescriptor> BuildTagHelperDescriptors(
|
||||
TypeInfo typeInfo,
|
||||
ITypeInfo typeInfo,
|
||||
string assemblyName,
|
||||
IEnumerable<TagHelperAttributeDescriptor> attributeDescriptors,
|
||||
IEnumerable<TargetElementAttribute> targetElementAttributes,
|
||||
|
|
@ -97,7 +95,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
#if !DNXCORE50
|
||||
if (designTime)
|
||||
{
|
||||
typeDesignTimeDescriptor = TagHelperDesignTimeDescriptorFactory.CreateDescriptor(typeInfo.AsType());
|
||||
var runtimeTypeInfo = typeInfo as RuntimeTypeInfo;
|
||||
if (runtimeTypeInfo != null)
|
||||
{
|
||||
typeDesignTimeDescriptor =
|
||||
TagHelperDesignTimeDescriptorFactory.CreateDescriptor(runtimeTypeInfo.TypeInfo.AsType());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -138,9 +141,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
typeDesignTimeDescriptor));
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GetAllowedChildren(TypeInfo typeInfo, ErrorSink errorSink)
|
||||
private static IEnumerable<string> GetAllowedChildren(ITypeInfo typeInfo, ErrorSink errorSink)
|
||||
{
|
||||
var restrictChildrenAttribute = typeInfo.GetCustomAttribute<RestrictChildrenAttribute>(inherit: false);
|
||||
var restrictChildrenAttribute = typeInfo
|
||||
.GetCustomAttributes<RestrictChildrenAttribute>()
|
||||
.FirstOrDefault();
|
||||
if (restrictChildrenAttribute == null)
|
||||
{
|
||||
return null;
|
||||
|
|
@ -338,7 +343,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
}
|
||||
|
||||
private static IEnumerable<TagHelperAttributeDescriptor> GetAttributeDescriptors(
|
||||
Type type,
|
||||
ITypeInfo type,
|
||||
bool designTime,
|
||||
ErrorSink errorSink)
|
||||
{
|
||||
|
|
@ -347,7 +352,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Keep indexer descriptors separate to avoid sorting the combined list later.
|
||||
var indexerDescriptors = new List<TagHelperAttributeDescriptor>();
|
||||
|
||||
var accessibleProperties = type.GetRuntimeProperties().Where(IsAccessibleProperty);
|
||||
var accessibleProperties = type.Properties.Where(IsAccessibleProperty);
|
||||
foreach (var property in accessibleProperties)
|
||||
{
|
||||
if (ShouldSkipDescriptorCreation(designTime, property))
|
||||
|
|
@ -355,13 +360,15 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
continue;
|
||||
}
|
||||
|
||||
var attributeNameAttribute = property.GetCustomAttribute<HtmlAttributeNameAttribute>(inherit: false);
|
||||
var attributeNameAttribute = property
|
||||
.GetCustomAttributes<HtmlAttributeNameAttribute>()
|
||||
.FirstOrDefault();
|
||||
var hasExplicitName =
|
||||
attributeNameAttribute != null && !string.IsNullOrEmpty(attributeNameAttribute.Name);
|
||||
var attributeName = hasExplicitName ? attributeNameAttribute.Name : ToHtmlCase(property.Name);
|
||||
|
||||
TagHelperAttributeDescriptor mainDescriptor = null;
|
||||
if (property.SetMethod?.IsPublic == true)
|
||||
if (property.HasPublicSetter)
|
||||
{
|
||||
mainDescriptor = ToAttributeDescriptor(property, attributeName, designTime);
|
||||
if (!ValidateTagHelperAttributeDescriptor(mainDescriptor, type, errorSink))
|
||||
|
|
@ -425,7 +432,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Internal for testing.
|
||||
internal static bool ValidateTagHelperAttributeDescriptor(
|
||||
TagHelperAttributeDescriptor attributeDescriptor,
|
||||
Type parentType,
|
||||
ITypeInfo parentType,
|
||||
ErrorSink errorSink)
|
||||
{
|
||||
string nameOrPrefix;
|
||||
|
|
@ -457,13 +464,16 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
nameOrPrefix);
|
||||
}
|
||||
|
||||
private static bool ShouldSkipDescriptorCreation(bool designTime, MemberInfo memberInfo)
|
||||
private static bool ShouldSkipDescriptorCreation(bool designTime, IMemberInfo memberInfo)
|
||||
{
|
||||
if (designTime)
|
||||
{
|
||||
var editorBrowsableAttribute = memberInfo.GetCustomAttribute<EditorBrowsableAttribute>(inherit: false);
|
||||
var editorBrowsableAttribute = memberInfo
|
||||
.GetCustomAttributes<EditorBrowsableAttribute>()
|
||||
.FirstOrDefault();
|
||||
|
||||
return editorBrowsableAttribute != null && editorBrowsableAttribute.State == EditorBrowsableState.Never;
|
||||
return editorBrowsableAttribute != null &&
|
||||
editorBrowsableAttribute.State == EditorBrowsableState.Never;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -471,7 +481,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
|
||||
private static bool ValidateTagHelperAttributeNameOrPrefix(
|
||||
string attributeNameOrPrefix,
|
||||
Type parentType,
|
||||
ITypeInfo parentType,
|
||||
string propertyName,
|
||||
ErrorSink errorSink,
|
||||
string nameOrPrefix)
|
||||
|
|
@ -540,7 +550,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
}
|
||||
|
||||
private static TagHelperAttributeDescriptor ToAttributeDescriptor(
|
||||
PropertyInfo property,
|
||||
IPropertyInfo property,
|
||||
string attributeName,
|
||||
bool designTime)
|
||||
{
|
||||
|
|
@ -553,21 +563,18 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
}
|
||||
|
||||
private static TagHelperAttributeDescriptor ToIndexerAttributeDescriptor(
|
||||
PropertyInfo property,
|
||||
IPropertyInfo property,
|
||||
HtmlAttributeNameAttribute attributeNameAttribute,
|
||||
Type parentType,
|
||||
ITypeInfo parentType,
|
||||
ErrorSink errorSink,
|
||||
string defaultPrefix,
|
||||
bool designTime,
|
||||
out bool isInvalid)
|
||||
{
|
||||
isInvalid = false;
|
||||
var hasPublicSetter = property.SetMethod?.IsPublic == true;
|
||||
var dictionaryTypeArguments = ClosedGenericMatcher.ExtractGenericInterface(
|
||||
property.PropertyType,
|
||||
typeof(IDictionary<,>))
|
||||
?.GenericTypeArguments;
|
||||
if (dictionaryTypeArguments?[0] != typeof(string))
|
||||
var hasPublicSetter = property.HasPublicSetter;
|
||||
var dictionaryTypeArguments = property.PropertyType.GetGenericDictionaryParameterNames();
|
||||
if (dictionaryTypeArguments?[0] != typeof(string).FullName)
|
||||
{
|
||||
if (attributeNameAttribute?.DictionaryAttributePrefix != null)
|
||||
{
|
||||
|
|
@ -634,13 +641,13 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
return ToAttributeDescriptor(
|
||||
property,
|
||||
attributeName: prefix,
|
||||
typeName: dictionaryTypeArguments[1].FullName,
|
||||
typeName: dictionaryTypeArguments[1],
|
||||
isIndexer: true,
|
||||
designTime: designTime);
|
||||
}
|
||||
|
||||
private static TagHelperAttributeDescriptor ToAttributeDescriptor(
|
||||
PropertyInfo property,
|
||||
IPropertyInfo property,
|
||||
string attributeName,
|
||||
string typeName,
|
||||
bool isIndexer,
|
||||
|
|
@ -651,8 +658,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
#if !DNXCORE50
|
||||
if (designTime)
|
||||
{
|
||||
propertyDesignTimeDescriptor =
|
||||
TagHelperDesignTimeDescriptorFactory.CreateAttributeDescriptor(property);
|
||||
var runtimeProperty = property as RuntimePropertyInfo;
|
||||
if (runtimeProperty != null)
|
||||
{
|
||||
propertyDesignTimeDescriptor =
|
||||
TagHelperDesignTimeDescriptorFactory.CreateAttributeDescriptor(runtimeProperty.Property);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -666,11 +677,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
};
|
||||
}
|
||||
|
||||
private static bool IsAccessibleProperty(PropertyInfo property)
|
||||
private static bool IsAccessibleProperty(IPropertyInfo property)
|
||||
{
|
||||
// Accessible properties are those with public getters and without [HtmlAttributeNotBound].
|
||||
return property.GetMethod?.IsPublic == true &&
|
||||
property.GetCustomAttribute<HtmlAttributeNotBoundAttribute>(inherit: false) == null;
|
||||
return property.HasPublicGetter &&
|
||||
property.GetCustomAttributes<HtmlAttributeNotBoundAttribute>().FirstOrDefault() == null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -17,25 +17,16 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
private static readonly TypeInfo ITagHelperTypeInfo = typeof(ITagHelper).GetTypeInfo();
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new instance of the <see cref="TagHelperTypeResolver"/> class.
|
||||
/// </summary>
|
||||
public TagHelperTypeResolver()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads an <see cref="Assembly"/> using the given <paramref name="name"/> and resolves
|
||||
/// all valid <see cref="ITagHelper"/> <see cref="Type"/>s.
|
||||
/// Locates valid <see cref="ITagHelper"/> types from the <see cref="Assembly"/> named <paramref name="name"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of an <see cref="Assembly"/> to search.</param>
|
||||
/// <param name="documentLocation">The <see cref="SourceLocation"/> of the associated
|
||||
/// <see cref="Parser.SyntaxTree.SyntaxTreeNode"/> responsible for the current <see cref="Resolve"/> call.
|
||||
/// </param>
|
||||
/// <param name="errorSink">The <see cref="ErrorSink"/> used to record errors found when resolving
|
||||
/// <see cref="ITagHelper"/> <see cref="Type"/>s.</param>
|
||||
/// <returns>An <see cref="IEnumerable{Type}"/> of valid <see cref="ITagHelper"/> <see cref="Type"/>s.
|
||||
/// </returns>
|
||||
public IEnumerable<Type> Resolve(
|
||||
/// <see cref="ITagHelper"/> types.</param>
|
||||
/// <returns>An <see cref="IEnumerable{ITypeInfo}"/> of valid <see cref="ITagHelper"/> types.</returns>
|
||||
public IEnumerable<ITypeInfo> Resolve(
|
||||
string name,
|
||||
SourceLocation documentLocation,
|
||||
[NotNull] ErrorSink errorSink)
|
||||
|
|
@ -48,15 +39,15 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
Resources.TagHelperTypeResolver_TagHelperAssemblyNameCannotBeEmptyOrNull,
|
||||
errorLength);
|
||||
|
||||
return Type.EmptyTypes;
|
||||
return Enumerable.Empty<ITypeInfo>();
|
||||
}
|
||||
|
||||
var assemblyName = new AssemblyName(name);
|
||||
|
||||
IEnumerable<TypeInfo> libraryTypes;
|
||||
IEnumerable<ITypeInfo> libraryTypes;
|
||||
try
|
||||
{
|
||||
libraryTypes = GetExportedTypes(assemblyName);
|
||||
libraryTypes = GetTopLevelExportedTypes(assemblyName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -67,13 +58,26 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
ex.Message),
|
||||
name.Length);
|
||||
|
||||
return Type.EmptyTypes;
|
||||
return Enumerable.Empty<ITypeInfo>();
|
||||
}
|
||||
|
||||
var validTagHelpers = libraryTypes.Where(IsTagHelper);
|
||||
return libraryTypes.Where(IsTagHelper);
|
||||
}
|
||||
|
||||
// Convert from TypeInfo[] to Type[]
|
||||
return validTagHelpers.Select(type => type.AsType());
|
||||
/// <summary>
|
||||
/// Returns all non-nested exported types from the given <paramref name="assemblyName"/>
|
||||
/// </summary>
|
||||
/// <param name="assemblyName">The <see cref="AssemblyName"/> to get <see cref="ITypeInfo"/>s from.</param>
|
||||
/// <returns>
|
||||
/// An <see cref="IEnumerable{ITypeInfo}"/> of types exported from the given <paramref name="assemblyName"/>.
|
||||
/// </returns>
|
||||
protected virtual IEnumerable<ITypeInfo> GetTopLevelExportedTypes([NotNull] AssemblyName assemblyName)
|
||||
{
|
||||
var exportedTypeInfos = GetExportedTypes(assemblyName);
|
||||
|
||||
return exportedTypeInfos
|
||||
.Where(typeInfo => !typeInfo.IsNested)
|
||||
.Select(typeInfo => new RuntimeTypeInfo(typeInfo));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -91,13 +95,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
}
|
||||
|
||||
// Internal for testing.
|
||||
internal virtual bool IsTagHelper(TypeInfo typeInfo)
|
||||
internal virtual bool IsTagHelper(ITypeInfo typeInfo)
|
||||
{
|
||||
return typeInfo.IsPublic &&
|
||||
!typeInfo.IsAbstract &&
|
||||
!typeInfo.IsGenericType &&
|
||||
!typeInfo.IsNested &&
|
||||
ITagHelperTypeInfo.IsAssignableFrom(typeInfo);
|
||||
typeInfo.IsTagHelper;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// 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.Fake
|
||||
{
|
||||
public class DoesNotImplementRealITagHelper : Microsoft.AspNet.Razor.Fake.ITagHelper
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Fake
|
||||
{
|
||||
public interface ITagHelper
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Fake
|
||||
{
|
||||
public class ImplementsRealITagHelper : Microsoft.AspNet.Razor.Runtime.TagHelpers.ITagHelper
|
||||
{
|
||||
public int Order
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
// 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.Linq;
|
||||
using System.Reflection;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||
{
|
||||
public class RuntimePropertyInfoTest
|
||||
{
|
||||
[Fact]
|
||||
public void PropertyInfo_ReturnsMetadataOfAdaptingProperty()
|
||||
{
|
||||
// Arrange
|
||||
var property = GetPropertyInfo(nameof(TestType.Property));
|
||||
var runtimePropertyInfo = new RuntimePropertyInfo(property);
|
||||
|
||||
// Act
|
||||
var actual = runtimePropertyInfo.Property;
|
||||
|
||||
// Assert
|
||||
Assert.Same(property, actual);
|
||||
var runtimeTypeInfo = Assert.IsType<RuntimeTypeInfo>(runtimePropertyInfo.PropertyType);
|
||||
Assert.Same(property.PropertyType, runtimeTypeInfo.TypeInfo);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(nameof(TestType.Property))]
|
||||
[InlineData(nameof(TestType.PrivateSetter))]
|
||||
[InlineData(nameof(TestType.PropertyWithoutSetter))]
|
||||
public void HasPublicGetter_ReturnsTrueIfGetterExistsAndIsPublic(string propertyName)
|
||||
{
|
||||
// Arrange
|
||||
var property = GetPropertyInfo(propertyName);
|
||||
var runtimePropertyInfo = new RuntimePropertyInfo(property);
|
||||
|
||||
// Act
|
||||
var result = runtimePropertyInfo.HasPublicGetter;
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(nameof(TestType.PrivateGetter))]
|
||||
[InlineData(nameof(TestType.PropertyWithoutGetter))]
|
||||
[InlineData("ProtectedProperty")]
|
||||
public void HasPublicGetter_ReturnsFalseIfGetterDoesNotExistOrIsNonPublic(string propertyName)
|
||||
{
|
||||
// Arrange
|
||||
var property = GetPropertyInfo(propertyName);
|
||||
var runtimePropertyInfo = new RuntimePropertyInfo(property);
|
||||
|
||||
// Act
|
||||
var result = runtimePropertyInfo.HasPublicGetter;
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(nameof(TestType.Property))]
|
||||
[InlineData(nameof(TestType.PrivateGetter))]
|
||||
[InlineData(nameof(TestType.PropertyWithoutGetter))]
|
||||
public void HasPublicSetter_ReturnsTrueIfSetterExistsAndIsPublic(string propertyName)
|
||||
{
|
||||
// Arrange
|
||||
var property = GetPropertyInfo(propertyName);
|
||||
var runtimePropertyInfo = new RuntimePropertyInfo(property);
|
||||
|
||||
// Act
|
||||
var result = runtimePropertyInfo.HasPublicSetter;
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(nameof(TestType.PrivateSetter))]
|
||||
[InlineData(nameof(TestType.PropertyWithoutSetter))]
|
||||
[InlineData("ProtectedProperty")]
|
||||
public void HasPublicSetter_ReturnsFalseIfGetterDoesNotExistOrIsNonPublic(string propertyName)
|
||||
{
|
||||
// Arrange
|
||||
var property = GetPropertyInfo(propertyName);
|
||||
var runtimePropertyInfo = new RuntimePropertyInfo(property);
|
||||
|
||||
// Act
|
||||
var result = runtimePropertyInfo.HasPublicSetter;
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAttributes_ReturnsCustomAttributesOfSpecifiedType()
|
||||
{
|
||||
// Arrange
|
||||
var property = GetPropertyInfo(nameof(TestType.PropertyWithAttributes));
|
||||
var runtimeProperty = new RuntimePropertyInfo(property);
|
||||
|
||||
// Act
|
||||
var attributes = property.GetCustomAttributes<HtmlAttributeNameAttribute>();
|
||||
|
||||
// Assert
|
||||
var htmlAttributeName = Assert.Single(attributes);
|
||||
Assert.Equal("somename", htmlAttributeName.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAttributes_DoesNotInheritAttributes()
|
||||
{
|
||||
// Arrange
|
||||
var property = GetPropertyInfo(nameof(TestType.PropertyWithAttributes));
|
||||
var runtimeProperty = new RuntimePropertyInfo(property);
|
||||
|
||||
// Act
|
||||
var attributes = property.GetCustomAttributes<HtmlAttributeNotBoundAttribute>();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(attributes);
|
||||
}
|
||||
|
||||
private static PropertyInfo GetPropertyInfo(string propertyName)
|
||||
{
|
||||
return typeof(TestType).GetRuntimeProperties()
|
||||
.FirstOrDefault(p => p.Name == propertyName);
|
||||
}
|
||||
|
||||
public class BaseType
|
||||
{
|
||||
[HtmlAttributeNotBound]
|
||||
public virtual string PropertyWithAttributes { get; }
|
||||
}
|
||||
|
||||
public class TestType : BaseType
|
||||
{
|
||||
public string Property { get; set; }
|
||||
|
||||
public int PrivateSetter { get; private set; }
|
||||
|
||||
public object PrivateGetter { private get; set; }
|
||||
|
||||
protected DateTimeOffset ProtectedProperty { get; set; }
|
||||
|
||||
public string PropertyWithoutGetter
|
||||
{
|
||||
set { }
|
||||
}
|
||||
|
||||
public int PropertyWithoutSetter => 0;
|
||||
|
||||
[HtmlAttributeName("somename")]
|
||||
public override string PropertyWithAttributes { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,375 @@
|
|||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
||||
{
|
||||
public class RuntimeTypeInfoTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(typeof(int))]
|
||||
[InlineData(typeof(string))]
|
||||
[InlineData(typeof(Tuple<,>))]
|
||||
[InlineData(typeof(IDictionary<string, string>))]
|
||||
[InlineData(typeof(IDictionary<string, IDictionary<string, CustomType>>))]
|
||||
[InlineData(typeof(AbstractType))]
|
||||
[InlineData(typeof(PrivateType))]
|
||||
[InlineData(typeof(KnownKeyDictionary<>))]
|
||||
[InlineData(typeof(KnownKeyDictionary<string>))]
|
||||
public void RuntimeTypeInfo_ReturnsMetadataOfAdaptingType(Type type)
|
||||
{
|
||||
// Arrange
|
||||
var typeInfo = type.GetTypeInfo();
|
||||
var runtimeTypeInfo = new RuntimeTypeInfo(typeInfo);
|
||||
|
||||
// Act and Assert
|
||||
Assert.Same(runtimeTypeInfo.TypeInfo, typeInfo);
|
||||
Assert.Equal(runtimeTypeInfo.Name, typeInfo.Name);
|
||||
Assert.Equal(runtimeTypeInfo.FullName, typeInfo.FullName);
|
||||
Assert.Equal(runtimeTypeInfo.IsAbstract, typeInfo.IsAbstract);
|
||||
Assert.Equal(runtimeTypeInfo.IsGenericType, typeInfo.IsGenericType);
|
||||
Assert.Equal(runtimeTypeInfo.IsPublic, typeInfo.IsPublic);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Properties_ReturnsPublicPropertiesOfAdaptingType()
|
||||
{
|
||||
// Arrange
|
||||
var typeInfo = typeof(SubType).GetTypeInfo();
|
||||
var runtimeTypeInfo = new RuntimeTypeInfo(typeInfo);
|
||||
|
||||
// Act and Assert
|
||||
Assert.Collection(runtimeTypeInfo.Properties,
|
||||
property =>
|
||||
{
|
||||
Assert.IsType<RuntimePropertyInfo>(property);
|
||||
Assert.Equal("Property1", property.Name);
|
||||
},
|
||||
property =>
|
||||
{
|
||||
Assert.IsType<RuntimePropertyInfo>(property);
|
||||
Assert.Equal("Property2", property.Name);
|
||||
},
|
||||
property =>
|
||||
{
|
||||
Assert.IsType<RuntimePropertyInfo>(property);
|
||||
Assert.Equal("Property3", property.Name);
|
||||
},
|
||||
property =>
|
||||
{
|
||||
Assert.IsType<RuntimePropertyInfo>(property);
|
||||
Assert.Equal("Property4", property.Name);
|
||||
},
|
||||
property =>
|
||||
{
|
||||
Assert.IsType<RuntimePropertyInfo>(property);
|
||||
Assert.Equal("BaseTypeProperty", property.Name);
|
||||
},
|
||||
property =>
|
||||
{
|
||||
Assert.IsType<RuntimePropertyInfo>(property);
|
||||
Assert.Equal("ProtectedProperty", property.Name);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetCustomAttributes_ReturnsAllAttributesOfType()
|
||||
{
|
||||
// Arrange
|
||||
var typeInfo = typeof(TypeWithAttributes).GetTypeInfo();
|
||||
var runtimeTypeInfo = new RuntimeTypeInfo(typeInfo);
|
||||
var expected = typeInfo.GetCustomAttributes<TargetElementAttribute>();
|
||||
|
||||
// Act
|
||||
var actual = runtimeTypeInfo.GetCustomAttributes<TargetElementAttribute>();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetCustomAttributes_DoesNotInheritAttributesFromBaseType()
|
||||
{
|
||||
// Arrange
|
||||
var typeInfo = typeof(SubType).GetTypeInfo();
|
||||
var runtimeTypeInfo = new RuntimeTypeInfo(typeInfo);
|
||||
|
||||
// Act
|
||||
var actual = runtimeTypeInfo.GetCustomAttributes<EditorBrowsableAttribute>();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(typeof(ITagHelper))]
|
||||
[InlineData(typeof(TagHelper))]
|
||||
[InlineData(typeof(ImplementsITagHelper))]
|
||||
[InlineData(typeof(DerivesFromTagHelper))]
|
||||
[InlineData(typeof(Fake.ImplementsRealITagHelper))]
|
||||
public void IsTagHelper_ReturnsTrueIfTypeImplementsTagHelper(Type type)
|
||||
{
|
||||
// Arrange
|
||||
var runtimeTypeInfo = new RuntimeTypeInfo(type.GetTypeInfo());
|
||||
|
||||
// Act
|
||||
var result = runtimeTypeInfo.IsTagHelper;
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(typeof(string))]
|
||||
[InlineData(typeof(SubType))]
|
||||
[InlineData(typeof(Fake.DoesNotImplementRealITagHelper))]
|
||||
public void IsTagHelper_ReturnsFalseIfTypeDoesNotImplementTagHelper(Type type)
|
||||
{
|
||||
// Arrange
|
||||
var runtimeTypeInfo = new RuntimeTypeInfo(type.GetTypeInfo());
|
||||
|
||||
// Act
|
||||
var result = runtimeTypeInfo.IsTagHelper;
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(typeof(Dictionary<string, string>), new[] { typeof(string), typeof(string) })]
|
||||
[InlineData(typeof(DerivesFromDictionary), new[] { typeof(int), typeof(object) })]
|
||||
[InlineData(typeof(ImplementsIDictionary), new[] { typeof(List<string>), typeof(string) })]
|
||||
[InlineData(typeof(IDictionary<string, IDictionary<string, CustomType>>),
|
||||
new[] { typeof(string), typeof(IDictionary<string, CustomType>) })]
|
||||
[InlineData(typeof(Dictionary<,>), new Type[] { null, null })]
|
||||
[InlineData(typeof(KnownKeyDictionary<>), new[] { typeof(string), null })]
|
||||
[InlineData(typeof(KnownKeyDictionary<ImplementsIDictionary>),
|
||||
new[] { typeof(string), typeof(ImplementsIDictionary) })]
|
||||
public void GetGenericDictionaryParameterNames_ReturnsKeyAndValueParameterTypeNames(
|
||||
Type type,
|
||||
Type[] expectedTypes)
|
||||
{
|
||||
// Arrange
|
||||
var runtimeTypeInfo = new RuntimeTypeInfo(type.GetTypeInfo());
|
||||
var expected = expectedTypes.Select(t => t?.FullName);
|
||||
|
||||
// Act
|
||||
var actual = runtimeTypeInfo.GetGenericDictionaryParameterNames();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(typeof(int))]
|
||||
[InlineData(typeof(string))]
|
||||
[InlineData(typeof(List<string>))]
|
||||
[InlineData(typeof(IDictionary))]
|
||||
[InlineData(typeof(ITagHelper))]
|
||||
public void GetGenericDictionaryParameterNames_ReturnsNullIfTypeDoesNotImplementGenericDictionary(Type type)
|
||||
{
|
||||
// Arrange
|
||||
var runtimeTypeInfo = new RuntimeTypeInfo(type.GetTypeInfo());
|
||||
|
||||
// Act
|
||||
var actual = runtimeTypeInfo.GetGenericDictionaryParameterNames();
|
||||
|
||||
// Assert
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
public class AbstractType
|
||||
{
|
||||
}
|
||||
|
||||
internal class InternalType
|
||||
{
|
||||
}
|
||||
|
||||
private class PrivateType
|
||||
{
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
private class BaseType
|
||||
{
|
||||
public string this[string key]
|
||||
{
|
||||
get { return ""; }
|
||||
set { }
|
||||
}
|
||||
|
||||
public string BaseTypeProperty { get; set; }
|
||||
|
||||
protected int ProtectedProperty { get; set; }
|
||||
}
|
||||
|
||||
private class SubType : BaseType
|
||||
{
|
||||
public string Property1 { get; set; }
|
||||
|
||||
public int Property2 { get; }
|
||||
|
||||
public object Property3 { private get; set; }
|
||||
|
||||
private int Property4 { get; set; }
|
||||
}
|
||||
|
||||
[TargetElement("test1")]
|
||||
[TargetElement("test2")]
|
||||
private class TypeWithAttributes
|
||||
{
|
||||
}
|
||||
|
||||
private class DerivesFromTagHelper : TagHelper
|
||||
{
|
||||
}
|
||||
|
||||
private class ImplementsITagHelper : ITagHelper
|
||||
{
|
||||
public int Order { get; } = 0;
|
||||
|
||||
public Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private class DerivesFromDictionary : Dictionary<int, object>
|
||||
{
|
||||
}
|
||||
|
||||
private class ImplementsIDictionary : IDictionary<List<string>, string>, IReadOnlyList<int>
|
||||
{
|
||||
public int this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public string this[List<string> key]
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<List<string>> Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<string> Values
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<List<string>, string> item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Add(List<string> key, string value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<List<string>, string> item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool ContainsKey(List<string> key)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<List<string>, string>[] array, int arrayIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<List<string>, string>> GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<List<string>, string> item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Remove(List<string> key)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool TryGetValue(List<string> key, out string value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
IEnumerator<int> IEnumerable<int>.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public class KnownKeyDictionary<TValue> : Dictionary<string, TValue>
|
||||
{
|
||||
}
|
||||
|
||||
private class CustomType
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -86,7 +86,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
tagHelperType,
|
||||
GetTypeInfo(tagHelperType),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -175,7 +175,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
tagHelperType,
|
||||
GetTypeInfo(tagHelperType),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -256,7 +256,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
tagHelperType,
|
||||
GetTypeInfo(tagHelperType),
|
||||
designTime: true,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -493,7 +493,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
tagHelperType,
|
||||
GetTypeInfo(tagHelperType),
|
||||
designTime,
|
||||
errorSink);
|
||||
|
||||
|
|
@ -695,7 +695,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
tagHelperType,
|
||||
GetTypeInfo(tagHelperType),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -744,7 +744,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
tagHelperType,
|
||||
GetTypeInfo(tagHelperType),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -781,7 +781,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
typeof(OverriddenAttributeTagHelper),
|
||||
GetTypeInfo(typeof(OverriddenAttributeTagHelper)),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -815,7 +815,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
typeof(InheritedOverriddenAttributeTagHelper),
|
||||
GetTypeInfo(typeof(InheritedOverriddenAttributeTagHelper)),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -849,7 +849,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
typeof(InheritedNotOverriddenAttributeTagHelper),
|
||||
GetTypeInfo(typeof(InheritedNotOverriddenAttributeTagHelper)),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -870,7 +870,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
objectAssemblyName,
|
||||
typeof(object),
|
||||
GetTypeInfo(typeof(object)),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -902,7 +902,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
typeof(InheritedSingleAttributeTagHelper),
|
||||
GetTypeInfo(typeof(InheritedSingleAttributeTagHelper)),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -930,7 +930,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
typeof(SingleAttributeTagHelper),
|
||||
GetTypeInfo(typeof(SingleAttributeTagHelper)),
|
||||
designTime: false,
|
||||
errorSink: new ErrorSink());
|
||||
|
||||
|
|
@ -959,7 +959,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
typeof(MissingAccessorTagHelper),
|
||||
GetTypeInfo(typeof(MissingAccessorTagHelper)),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -988,7 +988,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
typeof(NonPublicAccessorTagHelper),
|
||||
GetTypeInfo(typeof(NonPublicAccessorTagHelper)),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -1020,7 +1020,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
typeof(NotBoundAttributeTagHelper),
|
||||
GetTypeInfo(typeof(NotBoundAttributeTagHelper)),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -1039,7 +1039,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
typeof(DuplicateAttributeNameTagHelper),
|
||||
GetTypeInfo(typeof(DuplicateAttributeNameTagHelper)),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -1086,7 +1086,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
typeof(MultiTagTagHelper),
|
||||
GetTypeInfo(typeof(MultiTagTagHelper)),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -1118,7 +1118,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
typeof(InheritedMultiTagTagHelper),
|
||||
GetTypeInfo(typeof(InheritedMultiTagTagHelper)),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -1148,7 +1148,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
typeof(DuplicateTagNameTagHelper),
|
||||
GetTypeInfo(typeof(DuplicateTagNameTagHelper)),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -1178,7 +1178,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
typeof(OverrideNameTagHelper),
|
||||
GetTypeInfo(typeof(OverrideNameTagHelper)),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -1366,7 +1366,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
type,
|
||||
GetTypeInfo(type),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -1597,7 +1597,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var descriptors = TagHelperDescriptorFactory.CreateDescriptors(
|
||||
AssemblyName,
|
||||
tagHelperType,
|
||||
GetTypeInfo(tagHelperType),
|
||||
designTime: false,
|
||||
errorSink: errorSink);
|
||||
|
||||
|
|
@ -1651,7 +1651,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var result = TagHelperDescriptorFactory.ValidateTagHelperAttributeDescriptor(
|
||||
descriptor,
|
||||
typeof(MultiTagTagHelper),
|
||||
GetTypeInfo(typeof(MultiTagTagHelper)),
|
||||
errorSink);
|
||||
|
||||
// Assert
|
||||
|
|
@ -1693,7 +1693,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var result = TagHelperDescriptorFactory.ValidateTagHelperAttributeDescriptor(
|
||||
descriptor,
|
||||
typeof(MultiTagTagHelper),
|
||||
GetTypeInfo(typeof(MultiTagTagHelper)),
|
||||
errorSink);
|
||||
|
||||
// Assert
|
||||
|
|
@ -1739,7 +1739,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var result = TagHelperDescriptorFactory.ValidateTagHelperAttributeDescriptor(
|
||||
descriptor,
|
||||
typeof(MultiTagTagHelper),
|
||||
GetTypeInfo(typeof(MultiTagTagHelper)),
|
||||
errorSink);
|
||||
|
||||
// Assert
|
||||
|
|
@ -1794,7 +1794,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
// Act
|
||||
var result = TagHelperDescriptorFactory.ValidateTagHelperAttributeDescriptor(
|
||||
descriptor,
|
||||
typeof(MultiTagTagHelper),
|
||||
GetTypeInfo(typeof(MultiTagTagHelper)),
|
||||
errorSink);
|
||||
|
||||
// Assert
|
||||
|
|
@ -2101,6 +2101,9 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
};
|
||||
}
|
||||
|
||||
private static ITypeInfo GetTypeInfo(Type tagHelperType) =>
|
||||
new RuntimeTypeInfo(tagHelperType.GetTypeInfo());
|
||||
|
||||
[RestrictChildren("p")]
|
||||
private class RestrictChildrenTagHelper
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1575,7 +1575,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
return types?.Select(type => type.GetTypeInfo()) ?? Enumerable.Empty<TypeInfo>();
|
||||
}
|
||||
|
||||
internal override bool IsTagHelper(TypeInfo typeInfo)
|
||||
internal override bool IsTagHelper(ITypeInfo typeInfo)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,17 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
|
|||
var types = tagHelperTypeResolver.Resolve("Foo", SourceLocation.Zero, new ErrorSink());
|
||||
|
||||
// Assert
|
||||
Assert.Equal(ValidTestableTagHelpers, types);
|
||||
Assert.Collection(types,
|
||||
type =>
|
||||
{
|
||||
var typeInfo = Assert.IsType<RuntimeTypeInfo>(type);
|
||||
Assert.Equal(typeof(Valid_PlainTagHelper).GetTypeInfo(), typeInfo.TypeInfo);
|
||||
},
|
||||
type =>
|
||||
{
|
||||
var typeInfo = Assert.IsType<RuntimeTypeInfo>(type);
|
||||
Assert.Equal(typeof(Valid_InheritedTagHelper).GetTypeInfo(), typeInfo.TypeInfo);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
Loading…
Reference in New Issue