Removing ITypeInfo and related types

This commit is contained in:
Pranav K 2016-01-11 17:42:17 -08:00
parent c05551e167
commit b4d631e2f6
18 changed files with 237 additions and 1535 deletions

View File

@ -1,30 +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;
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;
}
}

View File

@ -1,26 +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.
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; }
}
}

View File

@ -1,74 +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;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
/// <summary>
/// Contains type metadata.
/// </summary>
public interface ITypeInfo : IMemberInfo, IEquatable<ITypeInfo>
{
/// <summary>
/// Fully qualified name of the type.
/// </summary>
/// <remarks>
/// On CoreCLR, some BCL types get type forwarded to the full desktop framework implementations at
/// runtime. For e.g. we compile against System.String in System.Runtime which is type forwarded to
/// mscorlib at runtime. Consequently for generic types where the <see cref="FullName"/> includes the assembly
/// qualified name of generic parameters, FullNames would not match.
/// Use <see cref="IEquatable{ITypeInfo}.Equals(ITypeInfo)"/> to compare <see cref="ITypeInfo"/>s instead.
/// </remarks>
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.Compilation.TagHelpers.TagHelperAttributeDescriptor.IsIndexer"/>.
/// </remarks>
IEnumerable<IPropertyInfo> Properties { get; }
/// <summary>
/// Gets a value indicating whether the type is an <see cref="Enum"/>.
/// </summary>
bool IsEnum { 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 <param name="interfaceTypeInfo"/> interface.
/// </summary>
bool ImplementsInterface(ITypeInfo interfaceTypeInfo);
/// <summary>
/// Gets the <see cref="ITypeInfo[]"/> for the <c>TKey</c> and <c>TValue</c> parameters of
/// <see cref="IDictionary{TKey, TValue}"/>.
/// </summary>
/// <returns>
/// The <see cref="ITypeInfo"/> 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, <see cref="ITypeInfo" /> for generic type parameters is <c>null</c>.
/// </remarks>
ITypeInfo[] GetGenericDictionaryParameters();
}
}

View File

@ -1,54 +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 System.Reflection;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
/// <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(PropertyInfo propertyInfo)
{
if (propertyInfo == null)
{
throw new ArgumentNullException(nameof(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();
}
}

View File

@ -1,182 +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 System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.Extensions.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 Regex _fullNameSanitizer = new Regex(
@", [A-Za-z\.]+, Version=\d+\.\d+\.\d+\.\d+, Culture=neutral, PublicKeyToken=\w+",
RegexOptions.ExplicitCapture,
Constants.RegexMatchTimeout);
private static readonly TypeInfo TagHelperTypeInfo = typeof(ITagHelper).GetTypeInfo();
private IEnumerable<IPropertyInfo> _properties;
private string _sanitizedFullName;
/// <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(TypeInfo typeInfo)
{
if (typeInfo == null)
{
throw new ArgumentNullException(nameof(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 IsEnum => TypeInfo.IsEnum;
/// <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 ImplementsInterface(ITypeInfo interfaceTypeInfo)
{
if (interfaceTypeInfo == null)
{
throw new ArgumentNullException(nameof(interfaceTypeInfo));
}
var runtimeTypeInfo = interfaceTypeInfo as RuntimeTypeInfo;
if (runtimeTypeInfo == null)
{
throw new ArgumentException(
Resources.FormatArgumentMustBeAnInstanceOf(typeof(RuntimeTypeInfo).FullName),
nameof(interfaceTypeInfo));
}
return runtimeTypeInfo.TypeInfo.IsInterface && runtimeTypeInfo.TypeInfo.IsAssignableFrom(TypeInfo);
}
private string SanitizedFullName
{
get
{
if (_sanitizedFullName == null)
{
_sanitizedFullName = SanitizeFullName(FullName);
}
return _sanitizedFullName;
}
}
/// <inheritdoc />
public IEnumerable<TAttribute> GetCustomAttributes<TAttribute>() where TAttribute : Attribute =>
TypeInfo.GetCustomAttributes<TAttribute>(inherit: false);
/// <inheritdoc />
public ITypeInfo[] GetGenericDictionaryParameters()
{
return ClosedGenericMatcher.ExtractGenericInterface(
TypeInfo.AsType(),
typeof(IDictionary<,>))
?.GenericTypeArguments
.Select(type => type.IsGenericParameter ? null : new RuntimeTypeInfo(type.GetTypeInfo()))
.ToArray();
}
/// <inheritdoc />
public override string ToString() => TypeInfo.ToString();
/// <inheritdoc />
public override bool Equals(object obj)
{
return Equals(obj as ITypeInfo);
}
/// <inheritdoc />
public bool Equals(ITypeInfo other)
{
if (other == null)
{
return false;
}
var otherRuntimeType = other as RuntimeTypeInfo;
if (otherRuntimeType != null)
{
return otherRuntimeType.TypeInfo == TypeInfo;
}
return string.Equals(
SanitizedFullName,
SanitizeFullName(other.FullName),
StringComparison.Ordinal);
}
/// <inheritdoc />
public override int GetHashCode() => SanitizedFullName.GetHashCode();
/// <summary>
/// Removes assembly qualification from generic type parameters for the specified <paramref name="fullName"/>.
/// </summary>
/// <param name="fullName">Full name.</param>
/// <returns>Full name without fully qualified generic parameters.</returns>
/// <example>
/// <c>typeof(<see cref="List{string}"/>).FullName</c> is
/// List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]
/// <c>Sanitize(typeof(<see cref="List{string}"/>.FullName</c> returns
/// List`1[[System.String]
/// </example>
public static string SanitizeFullName(string fullName)
{
// In CoreCLR, some types (such as System.String) are type forwarded from System.Runtime
// to mscorlib at runtime. Type names of generic type parameters includes the assembly qualified name;
// consequently the type name generated at precompilation differs from the one at runtime. We'll
// avoid dealing with these inconsistencies by removing assembly information from TypeInfo.FullName.
return _fullNameSanitizer.Replace(fullName, string.Empty);
}
}
}

View File

@ -9,11 +9,12 @@ using System.Reflection;
using System.Text.RegularExpressions;
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.Extensions.Internal;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
/// <summary>
/// Factory for <see cref="TagHelperDescriptor"/>s from <see cref="ITypeInfo"/>s.
/// Factory for <see cref="TagHelperDescriptor"/>s from <see cref="Type"/>s.
/// </summary>
public class TagHelperDescriptorFactory
{
@ -31,8 +32,6 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
RegexOptions.None,
Constants.RegexMatchTimeout);
private static readonly ITypeInfo StringTypeInfo = new RuntimeTypeInfo(typeof(string).GetTypeInfo());
#if !DOTNET5_4
private readonly TagHelperDesignTimeDescriptorFactory _designTimeDescriptorFactory;
#endif
@ -63,24 +62,24 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
}
/// <summary>
/// Creates a <see cref="TagHelperDescriptor"/> from the given <paramref name="typeInfo"/>.
/// Creates a <see cref="TagHelperDescriptor"/> from the given <paramref name="type"/>.
/// </summary>
/// <param name="assemblyName">The assembly name that contains <paramref name="type"/>.</param>
/// <param name="typeInfo">The <see cref="ITypeInfo"/> to create a <see cref="TagHelperDescriptor"/> from.
/// <param name="type">The <see cref="Type"/> to create a <see cref="TagHelperDescriptor"/> from.
/// </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="typeInfo"/>.</param>
/// when creating <see cref="TagHelperDescriptor"/>s for the given <paramref name="type"/>.</param>
/// <returns>
/// A collection of <see cref="TagHelperDescriptor"/>s that describe the given <paramref name="typeInfo"/>.
/// A collection of <see cref="TagHelperDescriptor"/>s that describe the given <paramref name="type"/>.
/// </returns>
public virtual IEnumerable<TagHelperDescriptor> CreateDescriptors(
string assemblyName,
ITypeInfo typeInfo,
Type type,
ErrorSink errorSink)
{
if (typeInfo == null)
if (type == null)
{
throw new ArgumentNullException(nameof(typeInfo));
throw new ArgumentNullException(nameof(type));
}
if (errorSink == null)
@ -88,18 +87,18 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
throw new ArgumentNullException(nameof(errorSink));
}
if (ShouldSkipDescriptorCreation(typeInfo))
if (ShouldSkipDescriptorCreation(type.GetTypeInfo()))
{
return Enumerable.Empty<TagHelperDescriptor>();
}
var attributeDescriptors = GetAttributeDescriptors(typeInfo, errorSink);
var targetElementAttributes = GetValidHtmlTargetElementAttributes(typeInfo, errorSink);
var allowedChildren = GetAllowedChildren(typeInfo, errorSink);
var attributeDescriptors = GetAttributeDescriptors(type, errorSink);
var targetElementAttributes = GetValidHtmlTargetElementAttributes(type, errorSink);
var allowedChildren = GetAllowedChildren(type, errorSink);
var tagHelperDescriptors =
BuildTagHelperDescriptors(
typeInfo,
type,
assemblyName,
attributeDescriptors,
targetElementAttributes,
@ -109,17 +108,18 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
}
private static IEnumerable<HtmlTargetElementAttribute> GetValidHtmlTargetElementAttributes(
ITypeInfo typeInfo,
Type type,
ErrorSink errorSink)
{
var targetElementAttributes = typeInfo.GetCustomAttributes<HtmlTargetElementAttribute>();
var targetElementAttributes = type
.GetTypeInfo()
.GetCustomAttributes<HtmlTargetElementAttribute>(inherit: false);
return targetElementAttributes.Where(
attribute => ValidHtmlTargetElementAttributeNames(attribute, errorSink));
}
private IEnumerable<TagHelperDescriptor> BuildTagHelperDescriptors(
ITypeInfo typeInfo,
Type type,
string assemblyName,
IEnumerable<TagHelperAttributeDescriptor> attributeDescriptors,
IEnumerable<HtmlTargetElementAttribute> targetElementAttributes,
@ -130,21 +130,16 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
#if !DOTNET5_4
if (_designTime)
{
var runtimeTypeInfo = typeInfo as RuntimeTypeInfo;
if (runtimeTypeInfo != null)
{
typeDesignTimeDescriptor =
_designTimeDescriptorFactory.CreateDescriptor(runtimeTypeInfo.TypeInfo.AsType());
}
typeDesignTimeDescriptor = _designTimeDescriptorFactory.CreateDescriptor(type);
}
#endif
var typeName = typeInfo.FullName;
var typeName = type.FullName;
// If there isn't an attribute specifying the tag name derive it from the name
if (!targetElementAttributes.Any())
{
var name = typeInfo.Name;
var name = type.Name;
if (name.EndsWith(TagHelperNameEnding, StringComparison.OrdinalIgnoreCase))
{
@ -177,18 +172,16 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
typeDesignTimeDescriptor));
}
private static IEnumerable<string> GetAllowedChildren(ITypeInfo typeInfo, ErrorSink errorSink)
private static IEnumerable<string> GetAllowedChildren(Type type, ErrorSink errorSink)
{
var restrictChildrenAttribute = typeInfo
.GetCustomAttributes<RestrictChildrenAttribute>()
.FirstOrDefault();
var restrictChildrenAttribute = type.GetTypeInfo().GetCustomAttribute<RestrictChildrenAttribute>(inherit: false);
if (restrictChildrenAttribute == null)
{
return null;
}
var allowedChildren = restrictChildrenAttribute.ChildTags;
var validAllowedChildren = GetValidAllowedChildren(allowedChildren, typeInfo.FullName, errorSink);
var validAllowedChildren = GetValidAllowedChildren(allowedChildren, type.FullName, errorSink);
if (validAllowedChildren.Any())
{
@ -405,14 +398,14 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
return validName;
}
private IEnumerable<TagHelperAttributeDescriptor> GetAttributeDescriptors(ITypeInfo type, ErrorSink errorSink)
private IEnumerable<TagHelperAttributeDescriptor> GetAttributeDescriptors(Type type, ErrorSink errorSink)
{
var attributeDescriptors = new List<TagHelperAttributeDescriptor>();
// Keep indexer descriptors separate to avoid sorting the combined list later.
var indexerDescriptors = new List<TagHelperAttributeDescriptor>();
var accessibleProperties = type.Properties.Where(IsAccessibleProperty);
var accessibleProperties = type.GetRuntimeProperties().Where(IsAccessibleProperty);
foreach (var property in accessibleProperties)
{
if (ShouldSkipDescriptorCreation(property))
@ -421,14 +414,14 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
}
var attributeNameAttribute = property
.GetCustomAttributes<HtmlAttributeNameAttribute>()
.GetCustomAttributes<HtmlAttributeNameAttribute>(inherit: false)
.FirstOrDefault();
var hasExplicitName =
attributeNameAttribute != null && !string.IsNullOrEmpty(attributeNameAttribute.Name);
var attributeName = hasExplicitName ? attributeNameAttribute.Name : ToHtmlCase(property.Name);
TagHelperAttributeDescriptor mainDescriptor = null;
if (property.HasPublicSetter)
if (property.SetMethod != null && property.SetMethod.IsPublic)
{
mainDescriptor = ToAttributeDescriptor(property, attributeName);
if (!ValidateTagHelperAttributeDescriptor(mainDescriptor, type, errorSink))
@ -491,7 +484,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Internal for testing.
internal static bool ValidateTagHelperAttributeDescriptor(
TagHelperAttributeDescriptor attributeDescriptor,
ITypeInfo parentType,
Type parentType,
ErrorSink errorSink)
{
string nameOrPrefix;
@ -523,13 +516,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
nameOrPrefix);
}
private bool ShouldSkipDescriptorCreation(IMemberInfo memberInfo)
private bool ShouldSkipDescriptorCreation(MemberInfo memberInfo)
{
if (_designTime)
{
var editorBrowsableAttribute = memberInfo
.GetCustomAttributes<EditorBrowsableAttribute>()
.FirstOrDefault();
var editorBrowsableAttribute = memberInfo.GetCustomAttribute<EditorBrowsableAttribute>(inherit: false);
return editorBrowsableAttribute != null &&
editorBrowsableAttribute.State == EditorBrowsableState.Never;
@ -540,7 +531,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
private static bool ValidateTagHelperAttributeNameOrPrefix(
string attributeNameOrPrefix,
ITypeInfo parentType,
Type parentType,
string propertyName,
ErrorSink errorSink,
string nameOrPrefix)
@ -608,28 +599,33 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
return isValid;
}
private TagHelperAttributeDescriptor ToAttributeDescriptor(IPropertyInfo property, string attributeName)
private TagHelperAttributeDescriptor ToAttributeDescriptor(PropertyInfo property, string attributeName)
{
return ToAttributeDescriptor(
property,
attributeName,
property.PropertyType.FullName,
isIndexer: false,
isStringProperty: StringTypeInfo.Equals(property.PropertyType));
isStringProperty: typeof(string) == property.PropertyType);
}
private TagHelperAttributeDescriptor ToIndexerAttributeDescriptor(
IPropertyInfo property,
PropertyInfo property,
HtmlAttributeNameAttribute attributeNameAttribute,
ITypeInfo parentType,
Type parentType,
ErrorSink errorSink,
string defaultPrefix,
out bool isInvalid)
{
isInvalid = false;
var hasPublicSetter = property.HasPublicSetter;
var dictionaryTypeArguments = property.PropertyType.GetGenericDictionaryParameters();
if (!StringTypeInfo.Equals(dictionaryTypeArguments?[0]))
var hasPublicSetter = property.SetMethod != null && property.SetMethod.IsPublic;
var dictionaryTypeArguments = ClosedGenericMatcher.ExtractGenericInterface(
property.PropertyType,
typeof(IDictionary<,>))
?.GenericTypeArguments
.Select(type => type.IsGenericParameter ? null : type)
.ToArray();
if (dictionaryTypeArguments?[0] != typeof(string))
{
if (attributeNameAttribute?.DictionaryAttributePrefix != null)
{
@ -698,11 +694,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
attributeName: prefix,
typeName: dictionaryTypeArguments[1].FullName,
isIndexer: true,
isStringProperty: StringTypeInfo.Equals(dictionaryTypeArguments[1]));
isStringProperty: typeof(string) == dictionaryTypeArguments[1]);
}
private TagHelperAttributeDescriptor ToAttributeDescriptor(
IPropertyInfo property,
PropertyInfo property,
string attributeName,
string typeName,
bool isIndexer,
@ -713,12 +709,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
#if !DOTNET5_4
if (_designTime)
{
var runtimeProperty = property as RuntimePropertyInfo;
if (runtimeProperty != null)
{
propertyDesignTimeDescriptor =
_designTimeDescriptorFactory.CreateAttributeDescriptor(runtimeProperty.Property);
}
propertyDesignTimeDescriptor = _designTimeDescriptorFactory.CreateAttributeDescriptor(property);
}
#endif
@ -726,7 +717,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
Name = attributeName,
PropertyName = property.Name,
IsEnum = property.PropertyType.IsEnum,
IsEnum = property.PropertyType.GetTypeInfo().IsEnum,
TypeName = typeName,
IsStringProperty = isStringProperty,
IsIndexer = isIndexer,
@ -734,11 +725,13 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
};
}
private static bool IsAccessibleProperty(IPropertyInfo property)
private static bool IsAccessibleProperty(PropertyInfo property)
{
// Accessible properties are those with public getters and without [HtmlAttributeNotBound].
return property.HasPublicGetter &&
property.GetCustomAttributes<HtmlAttributeNotBoundAttribute>().FirstOrDefault() == null;
return property.GetIndexParameters().Length == 0 &&
property.GetMethod != null &&
property.GetMethod.IsPublic &&
property.GetCustomAttribute<HtmlAttributeNotBoundAttribute>(inherit: false) == null;
}
/// <summary>

View File

@ -14,7 +14,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// </summary>
public class TagHelperTypeResolver
{
private static readonly ITypeInfo ITagHelperTypeInfo = new RuntimeTypeInfo(typeof(ITagHelper).GetTypeInfo());
private static readonly TypeInfo ITagHelperTypeInfo = typeof(ITagHelper).GetTypeInfo();
/// <summary>
/// Locates valid <see cref="ITagHelper"/> types from the <see cref="Assembly"/> named <paramref name="name"/>.
@ -25,8 +25,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
/// </param>
/// <param name="errorSink">The <see cref="ErrorSink"/> used to record errors found when resolving
/// <see cref="ITagHelper"/> types.</param>
/// <returns>An <see cref="IEnumerable{ITypeInfo}"/> of valid <see cref="ITagHelper"/> types.</returns>
public IEnumerable<ITypeInfo> Resolve(
/// <returns>An <see cref="IEnumerable{Type}"/> of valid <see cref="ITagHelper"/> types.</returns>
public IEnumerable<Type> Resolve(
string name,
SourceLocation documentLocation,
ErrorSink errorSink)
@ -44,15 +44,15 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Resources.TagHelperTypeResolver_TagHelperAssemblyNameCannotBeEmptyOrNull,
errorLength);
return Enumerable.Empty<ITypeInfo>();
return Type.EmptyTypes;
}
var assemblyName = new AssemblyName(name);
IEnumerable<ITypeInfo> libraryTypes;
IEnumerable<TypeInfo> libraryTypes;
try
{
libraryTypes = GetTopLevelExportedTypes(assemblyName);
libraryTypes = GetExportedTypes(assemblyName);
}
catch (Exception ex)
{
@ -63,31 +63,10 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
ex.Message),
name.Length);
return Enumerable.Empty<ITypeInfo>();
return Type.EmptyTypes;
}
return libraryTypes.Where(IsTagHelper);
}
/// <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(AssemblyName assemblyName)
{
if (assemblyName == null)
{
throw new ArgumentNullException(nameof(assemblyName));
}
var exportedTypeInfos = GetExportedTypes(assemblyName);
return exportedTypeInfos
.Where(typeInfo => !typeInfo.IsNested)
.Select(typeInfo => new RuntimeTypeInfo(typeInfo));
return libraryTypes.Where(IsTagHelper).Select(t => t.AsType());
}
/// <summary>
@ -105,12 +84,14 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
}
// Internal for testing.
internal virtual bool IsTagHelper(ITypeInfo typeInfo)
internal virtual bool IsTagHelper(TypeInfo typeInfo)
{
return typeInfo.IsPublic &&
!typeInfo.IsAbstract &&
!typeInfo.IsGenericType &&
typeInfo.ImplementsInterface(ITagHelperTypeInfo);
return
!typeInfo.IsNested &&
typeInfo.IsPublic &&
!typeInfo.IsAbstract &&
!typeInfo.IsGenericType &&
ITagHelperTypeInfo.IsAssignableFrom(typeInfo);
}
}
}

View File

@ -1,160 +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.Linq;
using System.Reflection;
using Microsoft.AspNet.Razor.TagHelpers;
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; }
}
}
}

View File

@ -1,159 +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 System.Linq;
using System.Reflection;
using Microsoft.AspNet.Razor.Compilation.TagHelpers;
using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.AspNet.Razor.Test.Internal;
using Xunit;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
public class RuntimeTagHelperDescriptorFactoryTest : TagHelperDescriptorFactoryTest
{
public override ITypeInfo GetTypeInfo(Type tagHelperType) =>
new RuntimeTypeInfo(tagHelperType.GetTypeInfo());
[Fact]
public void CreateDescriptors_BuildsDescriptorsFromSimpleTypes()
{
// Arrange
var errorSink = new ErrorSink();
var objectAssemblyName = typeof(object).GetTypeInfo().Assembly.GetName().Name;
var expectedDescriptor =
CreateTagHelperDescriptor("object", "System.Object", objectAssemblyName);
var factory = new TagHelperDescriptorFactory(designTime: false);
// Act
var descriptors = factory.CreateDescriptors(
objectAssemblyName,
GetTypeInfo(typeof(object)),
errorSink: errorSink);
// Assert
Assert.Empty(errorSink.Errors);
var descriptor = Assert.Single(descriptors);
Assert.Equal(expectedDescriptor, descriptor, CaseSensitiveTagHelperDescriptorComparer.Default);
}
[Theory]
[MemberData(nameof(TagHelperWithPrefixData))]
public void CreateDescriptors_WithPrefixes_ReturnsExpectedAttributeDescriptors(
Type tagHelperType,
IEnumerable<TagHelperAttributeDescriptor> expectedAttributeDescriptors,
string[] expectedErrorMessages)
{
// Arrange
var errorSink = new ErrorSink();
var factory = new TagHelperDescriptorFactory(designTime: false);
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(tagHelperType),
errorSink: errorSink);
// Assert
var errors = errorSink.Errors.ToArray();
Assert.Equal(expectedErrorMessages.Length, errors.Length);
for (var i = 0; i < errors.Length; i++)
{
Assert.Equal(0, errors[i].Length);
Assert.Equal(SourceLocation.Zero, errors[i].Location);
Assert.Equal(expectedErrorMessages[i], errors[i].Message, StringComparer.Ordinal);
}
var descriptor = Assert.Single(descriptors);
Assert.Equal(
expectedAttributeDescriptors,
descriptor.Attributes,
TagHelperAttributeDescriptorComparer.Default);
}
// TagHelperDesignTimeDescriptors are not created in CoreCLR.
#if !DNXCORE50
public static TheoryData OutputElementHintData
{
get
{
// tagHelperType, expectedDescriptors
return new TheoryData<Type, TagHelperDescriptor[]>
{
{
typeof(OutputElementHintTagHelper),
new[]
{
new TagHelperDescriptor
{
TagName = "output-element-hint",
TypeName = typeof(OutputElementHintTagHelper).FullName,
AssemblyName = AssemblyName,
DesignTimeDescriptor = new TagHelperDesignTimeDescriptor
{
OutputElementHint = "strong"
}
}
}
},
{
typeof(MulitpleDescriptorTagHelperWithOutputElementHint),
new[]
{
new TagHelperDescriptor
{
TagName = "a",
TypeName = typeof(MulitpleDescriptorTagHelperWithOutputElementHint).FullName,
AssemblyName = AssemblyName,
DesignTimeDescriptor = new TagHelperDesignTimeDescriptor
{
OutputElementHint = "div"
}
},
new TagHelperDescriptor
{
TagName = "p",
TypeName = typeof(MulitpleDescriptorTagHelperWithOutputElementHint).FullName,
AssemblyName = AssemblyName,
DesignTimeDescriptor = new TagHelperDesignTimeDescriptor
{
OutputElementHint = "div"
}
}
}
}
};
}
}
[Theory]
[MemberData(nameof(OutputElementHintData))]
public void CreateDescriptors_CreatesDesignTimeDescriptorsWithOutputElementHint(
Type tagHelperType,
TagHelperDescriptor[] expectedDescriptors)
{
// Arrange
var errorSink = new ErrorSink();
var factory = new TagHelperDescriptorFactory(designTime: true);
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(tagHelperType),
errorSink: errorSink);
// Assert
Assert.Empty(errorSink.Errors);
// We don't care about order. Mono returns reflected attributes differently so we need to ensure order
// doesn't matter by sorting.
descriptors = descriptors.OrderBy(descriptor => descriptor.TagName);
Assert.Equal(expectedDescriptors, descriptors, CaseSensitiveTagHelperDescriptorComparer.Default);
}
#endif
}
}

View File

@ -1,535 +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;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.AspNet.Testing;
using Xunit;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
public class RuntimeTypeInfoTest
{
[Theory]
[InlineData(typeof(int))]
[InlineData(typeof(string))]
[InlineData(typeof(Tuple<>))]
[InlineData(typeof(Tuple<>))]
[InlineData(typeof(IDictionary<string, string>))]
[InlineData(typeof(IDictionary<string, IDictionary<string, CustomType>>))]
[InlineData(typeof(IList<IReadOnlyList<IDictionary<List<string>, Tuple<CustomType, object[]>>>>))]
[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(typeInfo, runtimeTypeInfo.TypeInfo);
Assert.Equal(typeInfo.Name, runtimeTypeInfo.Name);
Assert.Equal(type.FullName, runtimeTypeInfo.FullName);
Assert.Equal(typeInfo.IsAbstract, runtimeTypeInfo.IsAbstract);
Assert.Equal(typeInfo.IsGenericType, runtimeTypeInfo.IsGenericType);
Assert.Equal(typeInfo.IsPublic, runtimeTypeInfo.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<HtmlTargetElementAttribute>();
// Act
var actual = runtimeTypeInfo.GetCustomAttributes<HtmlTargetElementAttribute>();
// 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);
}
[Fact]
public void ImplementsInterface_ThrowsIfArgumentIsNotRuntimeType()
{
// Arrange
var typeInfo = new RuntimeTypeInfo(typeof(object).GetTypeInfo());
var interfaceTypeInfo = new TestTypeInfo();
// Act and Assert
ExceptionAssert.ThrowsArgument(() => typeInfo.ImplementsInterface(interfaceTypeInfo),
"interfaceTypeInfo",
$"Argument must be an instance of '{typeof(RuntimeTypeInfo)}'.");
}
[Theory]
[InlineData(typeof(ITagHelper), typeof(ITagHelper))]
[InlineData(typeof(TagHelper), typeof(ITagHelper))]
[InlineData(typeof(ImplementsITagHelper), typeof(ITagHelper))]
[InlineData(typeof(DerivesFromTagHelper), typeof(ITagHelper))]
[InlineData(typeof(Fake.ImplementsRealITagHelper), typeof(ITagHelper))]
[InlineData(typeof(string), typeof(IEnumerable<char>))]
[InlineData(typeof(Dictionary<string, string>), typeof(IDictionary<string, string>))]
[InlineData(typeof(List<string>), typeof(IList<string>))]
[InlineData(typeof(IList<string>), typeof(IEnumerable<string>))]
public void ImplementsInterface_ReturnsTrueIfTypeImplementsInterface(Type runtimeType, Type interfaceType)
{
// Arrange
var runtimeTypeInfo = new RuntimeTypeInfo(runtimeType.GetTypeInfo());
var interfaceTypeInfo = new RuntimeTypeInfo(interfaceType.GetTypeInfo());
// Act
var result = runtimeTypeInfo.ImplementsInterface(interfaceTypeInfo);
// Assert
Assert.True(result);
}
[Theory]
[InlineData(typeof(string), typeof(object))]
[InlineData(typeof(DerivesFromTagHelper), typeof(TagHelper))]
[InlineData(typeof(string), typeof(ITagHelper))]
[InlineData(typeof(string), typeof(IList<char>))]
[InlineData(typeof(SubType), typeof(ITagHelper))]
[InlineData(typeof(Fake.DoesNotImplementRealITagHelper), typeof(ITagHelper))]
[InlineData(typeof(IDictionary<,>), typeof(IDictionary<string, string>))]
public void ImplementsInterface_ReturnsTrueIfTypeDoesNotImplementInterface(Type runtimeType, Type interfaceType)
{
// Arrange
var runtimeTypeInfo = new RuntimeTypeInfo(runtimeType.GetTypeInfo());
var interfaceTypeInfo = new RuntimeTypeInfo(interfaceType.GetTypeInfo());
// Act
var result = runtimeTypeInfo.ImplementsInterface(interfaceTypeInfo);
// 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(KnownKeyDictionary<ImplementsIDictionary>),
new[] { typeof(string), typeof(ImplementsIDictionary) })]
public void GetGenericDictionaryParameters_ReturnsKeyAndValueParameterTypeNames(
Type type,
Type[] expectedTypes)
{
// Arrange
var runtimeTypeInfo = new RuntimeTypeInfo(type.GetTypeInfo());
// Act
var actual = runtimeTypeInfo.GetGenericDictionaryParameters();
// Assert
Assert.Collection(actual,
keyType =>
{
Assert.Equal(new RuntimeTypeInfo(expectedTypes[0].GetTypeInfo()), keyType);
},
valueType =>
{
Assert.Equal(new RuntimeTypeInfo(expectedTypes[1].GetTypeInfo()), valueType);
});
}
[Fact]
public void GetGenericDictionaryParameters_WorksWhenValueParameterIsOpen()
{
// Arrange
var runtimeTypeInfo = new RuntimeTypeInfo(typeof(KnownKeyDictionary<>).GetTypeInfo());
// Act
var actual = runtimeTypeInfo.GetGenericDictionaryParameters();
// Assert
Assert.Collection(actual,
keyType =>
{
Assert.Equal(new RuntimeTypeInfo(typeof(string).GetTypeInfo()), keyType);
},
valueType =>
{
Assert.Null(valueType);
});
}
[Fact]
public void GetGenericDictionaryParameters_WorksWhenKeyAndValueParametersAreOpen()
{
// Arrange
var runtimeTypeInfo = new RuntimeTypeInfo(typeof(Dictionary<,>).GetTypeInfo());
// Act
var actual = runtimeTypeInfo.GetGenericDictionaryParameters();
// Assert
Assert.Equal(new RuntimeTypeInfo[] { null, null }, 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.GetGenericDictionaryParameters();
// Assert
Assert.Null(actual);
}
[Theory]
[InlineData(typeof(string))]
[InlineData(typeof(IDictionary<,>))]
[InlineData(typeof(ITagHelper))]
[InlineData(typeof(TagHelper))]
public void Equals_ReturnsTrueIfTypeInfosAreIdentical(Type type)
{
// Arrange
var typeA = new RuntimeTypeInfo(type.GetTypeInfo());
var typeB = new RuntimeTypeInfo(type.GetTypeInfo());
// Act
var equals = typeA.Equals(typeB);
var hashCodeA = typeA.GetHashCode();
var hashCodeB = typeB.GetHashCode();
// Assert
Assert.True(equals);
Assert.Equal(hashCodeA, hashCodeB);
}
public static TheoryData Equals_ReturnsTrueIfTypeFullNamesAreIdenticalData =>
new TheoryData<Type, string>
{
{ typeof(string), typeof(string).FullName },
{ typeof(ITagHelper), typeof(ITagHelper).FullName },
{ typeof(TagHelper), typeof(TagHelper).FullName },
{ typeof(TagHelper), typeof(TagHelper).FullName },
{ typeof(IDictionary<,>), typeof(IDictionary<,>).FullName },
{
typeof(IDictionary<string,string>),
typeof(IDictionary<string, string>).FullName
},
};
[Theory]
[MemberData(nameof(Equals_ReturnsTrueIfTypeFullNamesAreIdenticalData))]
public void Equals_ReturnsTrueIfTypeInfoNamesAreIdentical(Type type, string fullName)
{
// Arrange
var typeA = new RuntimeTypeInfo(type.GetTypeInfo());
var typeB = new TestTypeInfo
{
FullName = fullName
};
// Act
var equals = typeA.Equals(typeB);
// Assert
Assert.True(equals);
}
[Theory]
[InlineData(typeof(string), typeof(object))]
[InlineData(typeof(IDictionary<,>), typeof(IDictionary<string, string>))]
[InlineData(typeof(KnownKeyDictionary<string>), typeof(IDictionary<string, string>))]
[InlineData(typeof(ITagHelper), typeof(TagHelper))]
public void Equals_ReturnsFalseIfTypeInfosAreDifferent(Type typeA, Type typeB)
{
// Arrange
var typeAInfo = new RuntimeTypeInfo(typeA.GetTypeInfo());
var typeBInfo = new RuntimeTypeInfo(typeB.GetTypeInfo());
// Act
var equals = typeAInfo.Equals(typeBInfo);
var hashCodeA = typeAInfo.GetHashCode();
var hashCodeB = typeBInfo.GetHashCode();
// Assert
Assert.False(equals);
Assert.NotEqual(hashCodeA, hashCodeB);
}
[Theory]
[MemberData(nameof(Equals_ReturnsTrueIfTypeFullNamesAreIdenticalData))]
public void Equals_ReturnsFalseIfTypeInfoNamesAreDifferent(Type type, string fullName)
{
// Arrange
var typeA = new RuntimeTypeInfo(type.GetTypeInfo());
var typeB = new TestTypeInfo
{
FullName = "Different" + fullName
};
// Act
var equals = typeA.Equals(typeB);
// Assert
Assert.False(equals);
}
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; }
}
[HtmlTargetElement("test1")]
[HtmlTargetElement("test2")]
private class TypeWithAttributes
{
}
private class DerivesFromTagHelper : TagHelper
{
}
private class ImplementsITagHelper : ITagHelper
{
public int Order { get; } = 0;
public void Init(TagHelperContext context)
{
}
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
{
}
}
}

View File

@ -12,7 +12,7 @@ using Xunit;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
public abstract class TagHelperDescriptorFactoryTest
public class TagHelperDescriptorFactoryTest
{
protected static readonly AssemblyName TagHelperDescriptorFactoryTestAssembly =
typeof(TagHelperDescriptorFactoryTest).GetTypeInfo().Assembly.GetName();
@ -93,7 +93,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(tagHelperType),
tagHelperType,
errorSink: errorSink);
// Assert
@ -182,7 +182,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(tagHelperType),
tagHelperType,
errorSink: errorSink);
// Assert
@ -252,7 +252,6 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
}
}
public abstract ITypeInfo GetTypeInfo(Type tagHelperType);
[Theory]
[MemberData(nameof(RestrictChildrenData))]
@ -267,7 +266,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(tagHelperType),
tagHelperType,
errorSink: errorSink);
// Assert
@ -356,7 +355,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(tagHelperType),
tagHelperType,
errorSink: errorSink);
// Assert
@ -592,7 +591,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(tagHelperType),
tagHelperType,
errorSink);
// Assert
@ -794,7 +793,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(tagHelperType),
tagHelperType,
errorSink: errorSink);
// Assert
@ -843,7 +842,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(tagHelperType),
tagHelperType,
errorSink: errorSink);
// Assert
@ -880,7 +879,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(typeof(OverriddenAttributeTagHelper)),
typeof(OverriddenAttributeTagHelper),
errorSink: errorSink);
// Assert
@ -914,7 +913,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(typeof(InheritedOverriddenAttributeTagHelper)),
typeof(InheritedOverriddenAttributeTagHelper),
errorSink: errorSink);
// Assert
@ -948,7 +947,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(typeof(InheritedNotOverriddenAttributeTagHelper)),
typeof(InheritedNotOverriddenAttributeTagHelper),
errorSink: errorSink);
// Assert
Assert.Empty(errorSink.Errors);
@ -978,7 +977,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(typeof(InheritedSingleAttributeTagHelper)),
typeof(InheritedSingleAttributeTagHelper),
errorSink: errorSink);
// Assert
@ -1006,7 +1005,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(typeof(SingleAttributeTagHelper)),
typeof(SingleAttributeTagHelper),
errorSink: new ErrorSink());
// Assert
@ -1035,7 +1034,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(typeof(MissingAccessorTagHelper)),
typeof(MissingAccessorTagHelper),
errorSink: errorSink);
// Assert
@ -1064,7 +1063,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(typeof(NonPublicAccessorTagHelper)),
typeof(NonPublicAccessorTagHelper),
errorSink: errorSink);
// Assert
@ -1096,7 +1095,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(typeof(NotBoundAttributeTagHelper)),
typeof(NotBoundAttributeTagHelper),
errorSink: errorSink);
// Assert
@ -1115,7 +1114,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(typeof(DuplicateAttributeNameTagHelper)),
typeof(DuplicateAttributeNameTagHelper),
errorSink: errorSink);
// Assert
@ -1164,7 +1163,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(typeof(MultiTagTagHelper)),
typeof(MultiTagTagHelper),
errorSink: errorSink);
// Assert
@ -1196,7 +1195,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(typeof(InheritedMultiTagTagHelper)),
typeof(InheritedMultiTagTagHelper),
errorSink: errorSink);
// Assert
@ -1226,7 +1225,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(typeof(DuplicateTagNameTagHelper)),
typeof(DuplicateTagNameTagHelper),
errorSink: errorSink);
// Assert
@ -1256,7 +1255,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(typeof(OverrideNameTagHelper)),
typeof(OverrideNameTagHelper),
errorSink: errorSink);
// Assert
@ -1444,7 +1443,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
GetTypeInfo(type),
type,
errorSink: errorSink);
// Assert
@ -1694,7 +1693,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var result = TagHelperDescriptorFactory.ValidateTagHelperAttributeDescriptor(
descriptor,
GetTypeInfo(typeof(MultiTagTagHelper)),
typeof(MultiTagTagHelper),
errorSink);
// Assert
@ -1736,7 +1735,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var result = TagHelperDescriptorFactory.ValidateTagHelperAttributeDescriptor(
descriptor,
GetTypeInfo(typeof(MultiTagTagHelper)),
typeof(MultiTagTagHelper),
errorSink);
// Assert
@ -1782,7 +1781,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var result = TagHelperDescriptorFactory.ValidateTagHelperAttributeDescriptor(
descriptor,
GetTypeInfo(typeof(MultiTagTagHelper)),
typeof(MultiTagTagHelper),
errorSink);
// Assert
@ -1837,7 +1836,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
// Act
var result = TagHelperDescriptorFactory.ValidateTagHelperAttributeDescriptor(
descriptor,
GetTypeInfo(typeof(MultiTagTagHelper)),
typeof(MultiTagTagHelper),
errorSink);
// Assert
@ -1925,6 +1924,145 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Assert.Equal(expectedErrors, errorSink.Errors);
}
[Fact]
public void CreateDescriptors_BuildsDescriptorsFromSimpleTypes()
{
// Arrange
var errorSink = new ErrorSink();
var objectAssemblyName = typeof(object).GetTypeInfo().Assembly.GetName().Name;
var expectedDescriptor =
CreateTagHelperDescriptor("object", "System.Object", objectAssemblyName);
var factory = new TagHelperDescriptorFactory(designTime: false);
// Act
var descriptors = factory.CreateDescriptors(
objectAssemblyName,
typeof(object),
errorSink: errorSink);
// Assert
Assert.Empty(errorSink.Errors);
var descriptor = Assert.Single(descriptors);
Assert.Equal(expectedDescriptor, descriptor, CaseSensitiveTagHelperDescriptorComparer.Default);
}
[Theory]
[MemberData(nameof(TagHelperWithPrefixData))]
public void CreateDescriptors_WithPrefixes_ReturnsExpectedAttributeDescriptors(
Type tagHelperType,
IEnumerable<TagHelperAttributeDescriptor> expectedAttributeDescriptors,
string[] expectedErrorMessages)
{
// Arrange
var errorSink = new ErrorSink();
var factory = new TagHelperDescriptorFactory(designTime: false);
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
tagHelperType,
errorSink: errorSink);
// Assert
var errors = errorSink.Errors.ToArray();
Assert.Equal(expectedErrorMessages.Length, errors.Length);
for (var i = 0; i < errors.Length; i++)
{
Assert.Equal(0, errors[i].Length);
Assert.Equal(SourceLocation.Zero, errors[i].Location);
Assert.Equal(expectedErrorMessages[i], errors[i].Message, StringComparer.Ordinal);
}
var descriptor = Assert.Single(descriptors);
Assert.Equal(
expectedAttributeDescriptors,
descriptor.Attributes,
TagHelperAttributeDescriptorComparer.Default);
}
// TagHelperDesignTimeDescriptors are not created in CoreCLR.
#if !DNXCORE50
public static TheoryData OutputElementHintData
{
get
{
// tagHelperType, expectedDescriptors
return new TheoryData<Type, TagHelperDescriptor[]>
{
{
typeof(OutputElementHintTagHelper),
new[]
{
new TagHelperDescriptor
{
TagName = "output-element-hint",
TypeName = typeof(OutputElementHintTagHelper).FullName,
AssemblyName = AssemblyName,
DesignTimeDescriptor = new TagHelperDesignTimeDescriptor
{
OutputElementHint = "strong"
}
}
}
},
{
typeof(MulitpleDescriptorTagHelperWithOutputElementHint),
new[]
{
new TagHelperDescriptor
{
TagName = "a",
TypeName = typeof(MulitpleDescriptorTagHelperWithOutputElementHint).FullName,
AssemblyName = AssemblyName,
DesignTimeDescriptor = new TagHelperDesignTimeDescriptor
{
OutputElementHint = "div"
}
},
new TagHelperDescriptor
{
TagName = "p",
TypeName = typeof(MulitpleDescriptorTagHelperWithOutputElementHint).FullName,
AssemblyName = AssemblyName,
DesignTimeDescriptor = new TagHelperDesignTimeDescriptor
{
OutputElementHint = "div"
}
}
}
}
};
}
}
[Theory]
[MemberData(nameof(OutputElementHintData))]
public void CreateDescriptors_CreatesDesignTimeDescriptorsWithOutputElementHint(
Type tagHelperType,
TagHelperDescriptor[] expectedDescriptors)
{
// Arrange
var errorSink = new ErrorSink();
var factory = new TagHelperDescriptorFactory(designTime: true);
// Act
var descriptors = factory.CreateDescriptors(
AssemblyName,
tagHelperType,
errorSink: errorSink);
// Assert
Assert.Empty(errorSink.Errors);
// We don't care about order. Mono returns reflected attributes differently so we need to ensure order
// doesn't matter by sorting.
descriptors = descriptors.OrderBy(descriptor => descriptor.TagName);
Assert.Equal(expectedDescriptors, descriptors, CaseSensitiveTagHelperDescriptorComparer.Default);
}
#endif
private static TheoryData<string, string[]> GetInvalidNameOrPrefixData(
Func<string, string, string> onNameError,
string whitespaceErrorString,

View File

@ -1414,7 +1414,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
return types?.Select(type => type.GetTypeInfo()) ?? Enumerable.Empty<TypeInfo>();
}
internal override bool IsTagHelper(ITypeInfo typeInfo)
internal override bool IsTagHelper(TypeInfo typeInfo)
{
return true;
}

View File

@ -66,13 +66,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
Assert.Collection(types,
type =>
{
var typeInfo = Assert.IsType<RuntimeTypeInfo>(type);
Assert.Equal(typeof(Valid_PlainTagHelper).GetTypeInfo(), typeInfo.TypeInfo);
Assert.Equal(typeof(Valid_PlainTagHelper), type);
},
type =>
{
var typeInfo = Assert.IsType<RuntimeTypeInfo>(type);
Assert.Equal(typeof(Valid_InheritedTagHelper).GetTypeInfo(), typeInfo.TypeInfo);
Assert.Equal(typeof(Valid_InheritedTagHelper), type);
});
}

View File

@ -1,9 +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.
namespace Microsoft.AspNet.Razor.Fake
{
public class DoesNotImplementRealITagHelper : Microsoft.AspNet.Razor.Fake.ITagHelper
{
}
}

View File

@ -1,14 +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.Threading.Tasks;
using Microsoft.AspNet.Razor.TagHelpers;
namespace Microsoft.AspNet.Razor.Fake
{
public interface ITagHelper
{
}
}

View File

@ -1,30 +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.Threading.Tasks;
using Microsoft.AspNet.Razor.TagHelpers;
namespace Microsoft.AspNet.Razor.Fake
{
public class ImplementsRealITagHelper : Microsoft.AspNet.Razor.TagHelpers.ITagHelper
{
public int Order
{
get
{
throw new NotImplementedException();
}
}
public void Init(TagHelperContext context)
{
}
public Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
throw new NotImplementedException();
}
}
}

View File

@ -429,58 +429,4 @@ namespace Microsoft.AspNet.Razor.TagHelpers
public class MulitpleDescriptorTagHelperWithOutputElementHint : TagHelper
{
}
public class TypeDerivingFromITagHelper : ITagHelper
{
public int Order { get; } = 0;
public void Init(TagHelperContext context)
{
}
public Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
throw new NotImplementedException();
}
}
public class BaseAttribute : Attribute
{
public string BaseProperty { get; set; }
}
public class DerivedAttribute : BaseAttribute
{
public string DerivedProperty { get; set; }
}
public class BaseTagHelper : TagHelper
{
[Derived(DerivedProperty = "DerivedPropertyValue")]
public string BaseProperty { get; set; }
[HtmlAttributeNotBound]
public virtual string VirtualProperty { get; set; }
public int NewProperty { get; set; }
public virtual new string Order { get; set; }
}
public class DerivedTagHelper : BaseTagHelper
{
public override string VirtualProperty { get; set; }
[Base(BaseProperty = "BaseValue")]
public string DerivedProperty { get; set; }
[HtmlAttributeName("new-property")]
public new Type NewProperty { get; set; }
public override string Order { get; set; }
}
}
public class TagHelperInGlobalNamespace : TagHelper
{
}

View File

@ -1,81 +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;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
{
public class TestTypeInfo : ITypeInfo
{
public string FullName { get; set; }
public bool IsAbstract
{
get
{
throw new NotImplementedException();
}
}
public bool IsGenericType
{
get
{
throw new NotImplementedException();
}
}
public bool IsPublic
{
get
{
throw new NotImplementedException();
}
}
public bool IsEnum
{
get
{
throw new NotImplementedException();
}
}
public bool ImplementsInterface(ITypeInfo other)
{
throw new NotImplementedException();
}
public string Name
{
get
{
throw new NotImplementedException();
}
}
public IEnumerable<IPropertyInfo> Properties
{
get
{
throw new NotImplementedException();
}
}
public bool Equals(ITypeInfo other)
{
throw new NotImplementedException();
}
public IEnumerable<TAttribute> GetCustomAttributes<TAttribute>() where TAttribute : Attribute
{
throw new NotImplementedException();
}
public ITypeInfo[] GetGenericDictionaryParameters()
{
throw new NotImplementedException();
}
}
}