diff --git a/src/Microsoft.AspNet.Razor.Runtime.Precompilation/CodeAnalysisSymbolBasedTypeInfo.cs b/src/Microsoft.AspNet.Razor.Runtime.Precompilation/CodeAnalysisSymbolBasedTypeInfo.cs
index 81da1bbedc..61293d87a6 100644
--- a/src/Microsoft.AspNet.Razor.Runtime.Precompilation/CodeAnalysisSymbolBasedTypeInfo.cs
+++ b/src/Microsoft.AspNet.Razor.Runtime.Precompilation/CodeAnalysisSymbolBasedTypeInfo.cs
@@ -18,13 +18,8 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation
[DebuggerDisplay("{Name}")]
public class CodeAnalysisSymbolBasedTypeInfo : ITypeInfo
{
- ///
- /// The for .
- ///
- public static readonly System.Reflection.TypeInfo OpenGenericDictionaryTypeInfo =
+ private static readonly System.Reflection.TypeInfo OpenGenericDictionaryTypeInfo =
typeof(IDictionary<,>).GetTypeInfo();
- private static readonly System.Reflection.TypeInfo TagHelperTypeInfo =
- typeof(ITagHelper).GetTypeInfo();
private readonly ITypeSymbol _type;
private readonly ITypeSymbol _underlyingType;
private string _fullName;
@@ -120,13 +115,33 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation
}
///
- public bool IsTagHelper
+ public bool ImplementsInterface(ITypeInfo interfaceTypeInfo)
{
- get
+ if (interfaceTypeInfo == null)
{
- return _type.AllInterfaces.Any(
- implementedInterface => IsType(implementedInterface, TagHelperTypeInfo));
+ throw new ArgumentNullException(nameof(interfaceTypeInfo));
}
+
+ var runtimeTypeInfo = interfaceTypeInfo as RuntimeTypeInfo;
+ if (runtimeTypeInfo != null)
+ {
+ return runtimeTypeInfo.TypeInfo.IsInterface &&
+ _type.AllInterfaces.Any(implementedInterface => IsType(implementedInterface, runtimeTypeInfo.TypeInfo));
+ }
+
+ var codeAnalysisTypeInfo = interfaceTypeInfo as CodeAnalysisSymbolBasedTypeInfo;
+ if (codeAnalysisTypeInfo != null)
+ {
+ return codeAnalysisTypeInfo.TypeSymbol.TypeKind == TypeKind.Interface &&
+ _type.AllInterfaces.Any(
+ implementedInterface => implementedInterface == codeAnalysisTypeInfo.TypeSymbol);
+ }
+
+ throw new ArgumentException(
+ Resources.FormatArgumentMustBeAnInstanceOf(
+ typeof(RuntimeTypeInfo).FullName,
+ typeof(CodeAnalysisSymbolBasedTypeInfo).FullName),
+ nameof(interfaceTypeInfo));
}
private string SanitizedFullName
@@ -193,8 +208,8 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation
System.Reflection.TypeInfo targetTypeInfo)
{
return string.Equals(
- targetTypeInfo.FullName,
- GetFullName(sourceTypeSymbol),
+ RuntimeTypeInfo.SanitizeFullName(targetTypeInfo.FullName),
+ RuntimeTypeInfo.SanitizeFullName(GetFullName(sourceTypeSymbol)),
StringComparison.Ordinal);
}
diff --git a/src/Microsoft.AspNet.Razor.Runtime.Precompilation/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Razor.Runtime.Precompilation/Properties/Resources.Designer.cs
index cf3f1e0542..b7d61cc1c0 100644
--- a/src/Microsoft.AspNet.Razor.Runtime.Precompilation/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNet.Razor.Runtime.Precompilation/Properties/Resources.Designer.cs
@@ -10,6 +10,22 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.AspNet.Razor.Runtime.Precompilation.Resources", typeof(Resources).GetTypeInfo().Assembly);
+ ///
+ /// Argument must be an instance of '{0}' or '{1}'.
+ ///
+ internal static string ArgumentMustBeAnInstanceOf
+ {
+ get { return GetString("ArgumentMustBeAnInstanceOf"); }
+ }
+
+ ///
+ /// Argument must be an instance of '{0}' or '{1}'.
+ ///
+ internal static string FormatArgumentMustBeAnInstanceOf(object p0, object p1)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("ArgumentMustBeAnInstanceOf"), p0, p1);
+ }
+
///
/// Unable to find a suitable constructor for type '{0}'.
///
diff --git a/src/Microsoft.AspNet.Razor.Runtime.Precompilation/Resources.resx b/src/Microsoft.AspNet.Razor.Runtime.Precompilation/Resources.resx
index 4942941366..f8374b01b1 100644
--- a/src/Microsoft.AspNet.Razor.Runtime.Precompilation/Resources.resx
+++ b/src/Microsoft.AspNet.Razor.Runtime.Precompilation/Resources.resx
@@ -117,6 +117,9 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ Argument must be an instance of '{0}' or '{1}'.
+
Unable to find a suitable constructor for type '{0}'.
diff --git a/src/Microsoft.AspNet.Razor.Runtime/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Razor.Runtime/Properties/Resources.Designer.cs
index 5c731252c1..5dfc9ee0e4 100644
--- a/src/Microsoft.AspNet.Razor.Runtime/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNet.Razor.Runtime/Properties/Resources.Designer.cs
@@ -442,6 +442,22 @@ namespace Microsoft.AspNet.Razor.Runtime
return GetString("TagHelperDescriptorFactory_ParentTag");
}
+ ///
+ /// Argument must be an instance of '{0}'.
+ ///
+ internal static string ArgumentMustBeAnInstanceOf
+ {
+ get { return GetString("ArgumentMustBeAnInstanceOf"); }
+ }
+
+ ///
+ /// Argument must be an instance of '{0}'.
+ ///
+ internal static string FormatArgumentMustBeAnInstanceOf(object p0)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("ArgumentMustBeAnInstanceOf"), p0);
+ }
+
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
diff --git a/src/Microsoft.AspNet.Razor.Runtime/Resources.resx b/src/Microsoft.AspNet.Razor.Runtime/Resources.resx
index a1cdfa91b9..cfc6719220 100644
--- a/src/Microsoft.AspNet.Razor.Runtime/Resources.resx
+++ b/src/Microsoft.AspNet.Razor.Runtime/Resources.resx
@@ -1,17 +1,17 @@
-
@@ -198,4 +198,7 @@
Parent Tag
+
+ Argument must be an instance of '{0}'.
+
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/ITypeInfo.cs b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/ITypeInfo.cs
index f2b2f78a65..82995792e3 100644
--- a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/ITypeInfo.cs
+++ b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/ITypeInfo.cs
@@ -49,9 +49,9 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
bool IsGenericType { get; }
///
- /// Gets a value indicating whether the type implements the interface.
+ /// Gets a value indicating whether the type implements the interface.
///
- bool IsTagHelper { get; }
+ bool ImplementsInterface(ITypeInfo interfaceTypeInfo);
///
/// Gets the for the TKey and TValue parameters of
diff --git a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/RuntimeTypeInfo.cs b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/RuntimeTypeInfo.cs
index 6205ad5364..13df3baf0e 100644
--- a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/RuntimeTypeInfo.cs
+++ b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/RuntimeTypeInfo.cs
@@ -77,7 +77,23 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
}
///
- public bool IsTagHelper => TagHelperTypeInfo.IsAssignableFrom(TypeInfo);
+ 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
{
diff --git a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperTypeResolver.cs b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperTypeResolver.cs
index 2e3bf850d9..4f85ea405b 100644
--- a/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperTypeResolver.cs
+++ b/src/Microsoft.AspNet.Razor.Runtime/TagHelpers/TagHelperTypeResolver.cs
@@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
///
public class TagHelperTypeResolver
{
- private static readonly TypeInfo ITagHelperTypeInfo = typeof(ITagHelper).GetTypeInfo();
+ private static readonly ITypeInfo ITagHelperTypeInfo = new RuntimeTypeInfo(typeof(ITagHelper).GetTypeInfo());
///
/// Locates valid types from the named .
@@ -109,7 +109,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
return typeInfo.IsPublic &&
!typeInfo.IsAbstract &&
!typeInfo.IsGenericType &&
- typeInfo.IsTagHelper;
+ typeInfo.ImplementsInterface(ITagHelperTypeInfo);
}
}
}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Razor.Runtime.Precompilation.Files/DerivingFromIList.cs b/test/Microsoft.AspNet.Razor.Runtime.Precompilation.Files/DerivingFromIList.cs
new file mode 100644
index 0000000000..368247b8c1
--- /dev/null
+++ b/test/Microsoft.AspNet.Razor.Runtime.Precompilation.Files/DerivingFromIList.cs
@@ -0,0 +1,38 @@
+// 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;
+
+namespace Microsoft.AspNet.Razor.Runtime
+{
+ public class DerivingFromIList : IReadOnlyList
+ {
+ public string this[int index]
+ {
+ get
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public int Count
+ {
+ get
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ throw new NotImplementedException();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/test/Microsoft.AspNet.Razor.Runtime.Precompilation.Files/DerivingFromList.cs b/test/Microsoft.AspNet.Razor.Runtime.Precompilation.Files/DerivingFromList.cs
new file mode 100644
index 0000000000..db76f89170
--- /dev/null
+++ b/test/Microsoft.AspNet.Razor.Runtime.Precompilation.Files/DerivingFromList.cs
@@ -0,0 +1,11 @@
+// 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
+{
+ public class DerivingFromList : List
+ {
+ }
+}
diff --git a/test/Microsoft.AspNet.Razor.Runtime.Precompilation.Test/PrecompilationTagHelperTypeResolverTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Precompilation.Test/PrecompilationTagHelperTypeResolverTest.cs
index de8ae6d5cf..c82b86cbd1 100644
--- a/test/Microsoft.AspNet.Razor.Runtime.Precompilation.Test/PrecompilationTagHelperTypeResolverTest.cs
+++ b/test/Microsoft.AspNet.Razor.Runtime.Precompilation.Test/PrecompilationTagHelperTypeResolverTest.cs
@@ -8,6 +8,7 @@ using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
+using Microsoft.AspNet.Testing;
using Microsoft.CodeAnalysis.CSharp;
using Xunit;
@@ -15,7 +16,7 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation
{
public class PrecompilationTagHelperTypeResolverTest
{
- private static readonly TypeInfo TagHelperTypeInfo = typeof(ITagHelper).GetTypeInfo();
+ private static readonly ITypeInfo TagHelperTypeInfo = new RuntimeTypeInfo(typeof(ITagHelper).GetTypeInfo());
[Theory]
[InlineData(typeof(TypeDerivingFromITagHelper))]
@@ -35,6 +36,60 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation
AssertEqual(expected, actual);
}
+ [Fact]
+ public void ImplementsInterface_ThrowsIfPassedInParameterIsNotRuntimeTypeOrCodeAnalysisBasedTypeInfo()
+ {
+ // Arrange
+ var interfaceType = new TestTypeInfo();
+ var compilation = CompilationUtility.GetCompilation(nameof(DerivingFromList));
+ var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
+
+ // Act
+ var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
+
+ // Assert
+ var actual = Assert.Single(exportedTypes);
+ ExceptionAssert.ThrowsArgument(() => actual.ImplementsInterface(interfaceType),
+ "interfaceTypeInfo",
+ $"Argument must be an instance of '{typeof(RuntimeTypeInfo)}' or '{typeof(CodeAnalysisSymbolBasedTypeInfo)}'.");
+ }
+
+ [Theory]
+ [InlineData(typeof(DerivingFromList))]
+ [InlineData(typeof(DerivingFromIList))]
+ public void ImplementsInterface_ReturnsTrueIfTypeDerivesFromInterface(Type expected)
+ {
+ // Arrange
+ var interfaceType = new RuntimeTypeInfo(typeof(IEnumerable).GetTypeInfo());
+ var compilation = CompilationUtility.GetCompilation(expected.Name);
+ var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
+
+ // Act
+ var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
+
+ // Assert
+ var actual = Assert.Single(exportedTypes);
+ Assert.True(actual.ImplementsInterface(interfaceType));
+ }
+
+ [Theory]
+ [InlineData(typeof(TagHelper))]
+ [InlineData(typeof(IEnumerable))]
+ public void ImplementsInterface_ReturnsFalseIfTypeDoesNotDerivesFromInterface(Type interfaceType)
+ {
+ // Arrange
+ var interfaceTypeInfo = new RuntimeTypeInfo(interfaceType.GetTypeInfo());
+ var compilation = CompilationUtility.GetCompilation("TagHelperDescriptorFactoryTagHelpers");
+ var tagHelperResolver = new PrecompilationTagHelperTypeResolver(compilation);
+
+ // Act
+ var exportedTypes = tagHelperResolver.GetExportedTypes(compilation.AssemblyName);
+
+ // Assert
+ var actual = Assert.Single(exportedTypes, type => type.Name == nameof(RequiredParentTagHelper));
+ Assert.False(actual.ImplementsInterface(interfaceTypeInfo));
+ }
+
[Fact]
public void PropertyNamesForComplexPropertiesAreGeneratedCorrectly()
{
@@ -472,7 +527,7 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation
// Assert
var type = Assert.Single(exportedTypes);
- Assert.False(type.IsTagHelper);
+ Assert.False(type.ImplementsInterface(TagHelperTypeInfo));
}
private static void AssertAttributes(
@@ -481,7 +536,7 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation
Action assertItem)
where TAttribute : Attribute
{
- AssertAttributes(expected, actual, assertItem, attributes => attributes);
+ AssertAttributes(expected, actual, assertItem, attributes => attributes);
}
private static void AssertAttributes(
@@ -519,7 +574,9 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation
Assert.Equal(expected.IsPublic, actual.IsPublic);
Assert.Equal(expected.IsAbstract, actual.IsAbstract);
Assert.Equal(expected.IsGenericType, actual.IsGenericType);
- Assert.Equal(expected.IsTagHelper, actual.IsTagHelper);
+ Assert.Equal(
+ expected.ImplementsInterface(TagHelperTypeInfo),
+ actual.ImplementsInterface(TagHelperTypeInfo));
Assert.Equal(
expected.GetGenericDictionaryParameters(),
actual.GetGenericDictionaryParameters(),
diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/RuntimeTypeInfoTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/RuntimeTypeInfoTest.cs
index c84d6e611b..ff7b0f0d16 100644
--- a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/RuntimeTypeInfoTest.cs
+++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/RuntimeTypeInfoTest.cs
@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Threading.Tasks;
+using Microsoft.AspNet.Testing;
using Xunit;
namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
@@ -110,35 +111,58 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
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)
+ [Fact]
+ public void ImplementsInterface_ThrowsIfArgumentIsNotRuntimeType()
{
// Arrange
- var runtimeTypeInfo = new RuntimeTypeInfo(type.GetTypeInfo());
+ 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))]
+ [InlineData(typeof(Dictionary), typeof(IDictionary))]
+ [InlineData(typeof(List), typeof(IList))]
+ [InlineData(typeof(IList), typeof(IEnumerable))]
+ 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.IsTagHelper;
+ var result = runtimeTypeInfo.ImplementsInterface(interfaceTypeInfo);
// Assert
Assert.True(result);
}
[Theory]
- [InlineData(typeof(string))]
- [InlineData(typeof(SubType))]
- [InlineData(typeof(Fake.DoesNotImplementRealITagHelper))]
- public void IsTagHelper_ReturnsFalseIfTypeDoesNotImplementTagHelper(Type type)
+ [InlineData(typeof(string), typeof(object))]
+ [InlineData(typeof(DerivesFromTagHelper), typeof(TagHelper))]
+ [InlineData(typeof(string), typeof(ITagHelper))]
+ [InlineData(typeof(string), typeof(IList))]
+ [InlineData(typeof(SubType), typeof(ITagHelper))]
+ [InlineData(typeof(Fake.DoesNotImplementRealITagHelper), typeof(ITagHelper))]
+ [InlineData(typeof(IDictionary<,>), typeof(IDictionary))]
+ public void ImplementsInterface_ReturnsTrueIfTypeDoesNotImplementInterface(Type runtimeType, Type interfaceType)
{
// Arrange
- var runtimeTypeInfo = new RuntimeTypeInfo(type.GetTypeInfo());
+ var runtimeTypeInfo = new RuntimeTypeInfo(runtimeType.GetTypeInfo());
+ var interfaceTypeInfo = new RuntimeTypeInfo(interfaceType.GetTypeInfo());
// Act
- var result = runtimeTypeInfo.IsTagHelper;
+ var result = runtimeTypeInfo.ImplementsInterface(interfaceTypeInfo);
// Assert
Assert.False(result);
@@ -502,73 +526,5 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers
private class CustomType
{
}
-
- private 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 IsTagHelper
- {
- get
- {
- throw new NotImplementedException();
- }
- }
-
- public string Name
- {
- get
- {
- throw new NotImplementedException();
- }
- }
-
- public IEnumerable Properties
- {
- get
- {
- throw new NotImplementedException();
- }
- }
-
- public bool Equals(ITypeInfo other)
- {
- throw new NotImplementedException();
- }
-
- public IEnumerable GetCustomAttributes() where TAttribute : Attribute
- {
- throw new NotImplementedException();
- }
-
- public ITypeInfo[] GetGenericDictionaryParameters()
- {
- throw new NotImplementedException();
- }
- }
}
}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TestTagHelpers/TestTypeInfo.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TestTagHelpers/TestTypeInfo.cs
new file mode 100644
index 0000000000..97e4b90455
--- /dev/null
+++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TestTagHelpers/TestTypeInfo.cs
@@ -0,0 +1,73 @@
+// 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 ImplementsInterface(ITypeInfo other)
+ {
+ throw new NotImplementedException();
+ }
+
+ public string Name
+ {
+ get
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public IEnumerable Properties
+ {
+ get
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public bool Equals(ITypeInfo other)
+ {
+ throw new NotImplementedException();
+ }
+
+ public IEnumerable GetCustomAttributes() where TAttribute : Attribute
+ {
+ throw new NotImplementedException();
+ }
+
+ public ITypeInfo[] GetGenericDictionaryParameters()
+ {
+ throw new NotImplementedException();
+ }
+ }
+}