diff --git a/src/Microsoft.AspNet.Razor.Runtime/Runtime/TagHelpers/TagHelperDescriptorFactory.cs b/src/Microsoft.AspNet.Razor.Runtime/Runtime/TagHelpers/TagHelperDescriptorFactory.cs index c3504800a5..aae43d1ab8 100644 --- a/src/Microsoft.AspNet.Razor.Runtime/Runtime/TagHelpers/TagHelperDescriptorFactory.cs +++ b/src/Microsoft.AspNet.Razor.Runtime/Runtime/TagHelpers/TagHelperDescriptorFactory.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers /// /// Factory for s from s. /// - public static class TagHelperDescriptorFactory + public class TagHelperDescriptorFactory { private const string DataDashPrefix = "data-"; private const string TagHelperNameEnding = "TagHelper"; @@ -33,29 +33,49 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers private static readonly ITypeInfo StringTypeInfo = new RuntimeTypeInfo(typeof(string).GetTypeInfo()); +#if !DOTNET5_4 + private readonly TagHelperDesignTimeDescriptorFactory _designTimeDescriptorFactory; +#endif + private readonly bool _designTime; + // TODO: Investigate if we should cache TagHelperDescriptors for types: // https://github.com/aspnet/Razor/issues/165 public static ICollection InvalidNonWhitespaceNameCharacters { get; } = new HashSet( new[] { '@', '!', '<', '/', '?', '[', '>', ']', '=', '"', '\'', '*' }); + /// + /// Instantiates a new . + /// + /// + /// Indicates if s should be created for design time. + /// + public TagHelperDescriptorFactory(bool designTime) + { +#if !DOTNET5_4 + if (designTime) + { + _designTimeDescriptorFactory = new TagHelperDesignTimeDescriptorFactory(); + } +#endif + + _designTime = designTime; + } + /// /// Creates a from the given . /// /// The assembly name that contains . /// The to create a from. /// - /// Indicates if the returned s should include - /// design time specific information. /// The used to collect s encountered /// when creating s for the given . /// /// A collection of s that describe the given . /// - public static IEnumerable CreateDescriptors( + public virtual IEnumerable CreateDescriptors( string assemblyName, ITypeInfo typeInfo, - bool designTime, ErrorSink errorSink) { if (typeInfo == null) @@ -68,12 +88,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers throw new ArgumentNullException(nameof(errorSink)); } - if (ShouldSkipDescriptorCreation(designTime, typeInfo)) + if (ShouldSkipDescriptorCreation(typeInfo)) { return Enumerable.Empty(); } - var attributeDescriptors = GetAttributeDescriptors(typeInfo, designTime, errorSink); + var attributeDescriptors = GetAttributeDescriptors(typeInfo, errorSink); var targetElementAttributes = GetValidHtmlTargetElementAttributes(typeInfo, errorSink); var allowedChildren = GetAllowedChildren(typeInfo, errorSink); @@ -83,8 +103,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers assemblyName, attributeDescriptors, targetElementAttributes, - allowedChildren, - designTime); + allowedChildren); return tagHelperDescriptors.Distinct(TagHelperDescriptorComparer.Default); } @@ -99,24 +118,23 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers attribute => ValidHtmlTargetElementAttributeNames(attribute, errorSink)); } - private static IEnumerable BuildTagHelperDescriptors( + private IEnumerable BuildTagHelperDescriptors( ITypeInfo typeInfo, string assemblyName, IEnumerable attributeDescriptors, IEnumerable targetElementAttributes, - IEnumerable allowedChildren, - bool designTime) + IEnumerable allowedChildren) { TagHelperDesignTimeDescriptor typeDesignTimeDescriptor = null; #if !DOTNET5_4 - if (designTime) + if (_designTime) { var runtimeTypeInfo = typeInfo as RuntimeTypeInfo; if (runtimeTypeInfo != null) { typeDesignTimeDescriptor = - TagHelperDesignTimeDescriptorFactory.CreateDescriptor(runtimeTypeInfo.TypeInfo.AsType()); + _designTimeDescriptorFactory.CreateDescriptor(runtimeTypeInfo.TypeInfo.AsType()); } } #endif @@ -387,10 +405,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers return validName; } - private static IEnumerable GetAttributeDescriptors( - ITypeInfo type, - bool designTime, - ErrorSink errorSink) + private IEnumerable GetAttributeDescriptors(ITypeInfo type, ErrorSink errorSink) { var attributeDescriptors = new List(); @@ -400,7 +415,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var accessibleProperties = type.Properties.Where(IsAccessibleProperty); foreach (var property in accessibleProperties) { - if (ShouldSkipDescriptorCreation(designTime, property)) + if (ShouldSkipDescriptorCreation(property)) { continue; } @@ -415,7 +430,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers TagHelperAttributeDescriptor mainDescriptor = null; if (property.HasPublicSetter) { - mainDescriptor = ToAttributeDescriptor(property, attributeName, designTime); + mainDescriptor = ToAttributeDescriptor(property, attributeName); if (!ValidateTagHelperAttributeDescriptor(mainDescriptor, type, errorSink)) { // HtmlAttributeNameAttribute.Name is invalid. Ignore this property completely. @@ -443,7 +458,6 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers parentType: type, errorSink: errorSink, defaultPrefix: attributeName + "-", - designTime: designTime, isInvalid: out isInvalid); if (indexerDescriptor != null && !ValidateTagHelperAttributeDescriptor(indexerDescriptor, type, errorSink)) @@ -509,9 +523,9 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers nameOrPrefix); } - private static bool ShouldSkipDescriptorCreation(bool designTime, IMemberInfo memberInfo) + private bool ShouldSkipDescriptorCreation(IMemberInfo memberInfo) { - if (designTime) + if (_designTime) { var editorBrowsableAttribute = memberInfo .GetCustomAttributes() @@ -594,27 +608,22 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers return isValid; } - private static TagHelperAttributeDescriptor ToAttributeDescriptor( - IPropertyInfo property, - string attributeName, - bool designTime) + private TagHelperAttributeDescriptor ToAttributeDescriptor(IPropertyInfo property, string attributeName) { return ToAttributeDescriptor( property, attributeName, property.PropertyType.FullName, isIndexer: false, - isStringProperty: StringTypeInfo.Equals(property.PropertyType), - designTime: designTime); + isStringProperty: StringTypeInfo.Equals(property.PropertyType)); } - private static TagHelperAttributeDescriptor ToIndexerAttributeDescriptor( + private TagHelperAttributeDescriptor ToIndexerAttributeDescriptor( IPropertyInfo property, HtmlAttributeNameAttribute attributeNameAttribute, ITypeInfo parentType, ErrorSink errorSink, string defaultPrefix, - bool designTime, out bool isInvalid) { isInvalid = false; @@ -689,28 +698,26 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers attributeName: prefix, typeName: dictionaryTypeArguments[1].FullName, isIndexer: true, - isStringProperty: StringTypeInfo.Equals(dictionaryTypeArguments[1]), - designTime: designTime); + isStringProperty: StringTypeInfo.Equals(dictionaryTypeArguments[1])); } - private static TagHelperAttributeDescriptor ToAttributeDescriptor( + private TagHelperAttributeDescriptor ToAttributeDescriptor( IPropertyInfo property, string attributeName, string typeName, bool isIndexer, - bool isStringProperty, - bool designTime) + bool isStringProperty) { TagHelperAttributeDesignTimeDescriptor propertyDesignTimeDescriptor = null; #if !DOTNET5_4 - if (designTime) + if (_designTime) { var runtimeProperty = property as RuntimePropertyInfo; if (runtimeProperty != null) { propertyDesignTimeDescriptor = - TagHelperDesignTimeDescriptorFactory.CreateAttributeDescriptor(runtimeProperty.Property); + _designTimeDescriptorFactory.CreateAttributeDescriptor(runtimeProperty.Property); } } #endif diff --git a/src/Microsoft.AspNet.Razor.Runtime/Runtime/TagHelpers/TagHelperDescriptorResolver.cs b/src/Microsoft.AspNet.Razor.Runtime/Runtime/TagHelpers/TagHelperDescriptorResolver.cs index d96346ea0a..895d2e12cd 100644 --- a/src/Microsoft.AspNet.Razor.Runtime/Runtime/TagHelpers/TagHelperDescriptorResolver.cs +++ b/src/Microsoft.AspNet.Razor.Runtime/Runtime/TagHelpers/TagHelperDescriptorResolver.cs @@ -24,7 +24,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers }; private readonly TagHelperTypeResolver _typeResolver; - private readonly bool _designTime; + private readonly TagHelperDescriptorFactory _descriptorFactory; /// /// Instantiates a new instance of the class. @@ -32,7 +32,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers /// Indicates whether resolved s should include /// design time specific information. public TagHelperDescriptorResolver(bool designTime) - : this(new TagHelperTypeResolver(), designTime) + : this(new TagHelperTypeResolver(), new TagHelperDescriptorFactory(designTime)) { } @@ -41,12 +41,13 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers /// specified . /// /// The . - /// Indicates whether resolved s should include - /// design time specific information. - public TagHelperDescriptorResolver(TagHelperTypeResolver typeResolver, bool designTime) + /// The . + public TagHelperDescriptorResolver( + TagHelperTypeResolver typeResolver, + TagHelperDescriptorFactory descriptorFactory) { _typeResolver = typeResolver; - _designTime = designTime; + _descriptorFactory = descriptorFactory; } /// @@ -137,7 +138,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers // Convert types to TagHelperDescriptors var descriptors = tagHelperTypes.SelectMany( - type => TagHelperDescriptorFactory.CreateDescriptors(assemblyName, type, _designTime, errorSink)); + type => _descriptorFactory.CreateDescriptors(assemblyName, type, errorSink)); return descriptors; } diff --git a/src/Microsoft.AspNet.Razor.Runtime/Runtime/TagHelpers/TagHelperDesignTimeDescriptorFactory.cs b/src/Microsoft.AspNet.Razor.Runtime/Runtime/TagHelpers/TagHelperDesignTimeDescriptorFactory.cs index 22757e37a2..2912b79886 100644 --- a/src/Microsoft.AspNet.Razor.Runtime/Runtime/TagHelpers/TagHelperDesignTimeDescriptorFactory.cs +++ b/src/Microsoft.AspNet.Razor.Runtime/Runtime/TagHelpers/TagHelperDesignTimeDescriptorFactory.cs @@ -3,6 +3,7 @@ #if !DOTNET5_4 // Cannot accurately resolve the location of the documentation XML file in coreclr. using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -10,6 +11,7 @@ using System.Linq; using System.Reflection; using Microsoft.AspNet.Razor.Compilation.TagHelpers; using Microsoft.AspNet.Razor.TagHelpers; +using Microsoft.Extensions.Internal; namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { @@ -17,8 +19,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers /// Factory for providing s from s and /// s from s. /// - public static class TagHelperDesignTimeDescriptorFactory + public class TagHelperDesignTimeDescriptorFactory { + private readonly ConcurrentDictionary _documentationProviderCache = + new ConcurrentDictionary(); + /// /// Creates a from the given . /// @@ -27,7 +32,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers /// /// A that describes design time specific information /// for the given . - public static TagHelperDesignTimeDescriptor CreateDescriptor(Type type) + public TagHelperDesignTimeDescriptor CreateDescriptor(Type type) { if (type == null) { @@ -66,8 +71,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers /// /// A that describes design time specific /// information for the given . - public static TagHelperAttributeDesignTimeDescriptor CreateAttributeDescriptor( - PropertyInfo propertyInfo) + public TagHelperAttributeDesignTimeDescriptor CreateAttributeDescriptor(PropertyInfo propertyInfo) { if (propertyInfo == null) { @@ -77,7 +81,6 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var id = XmlDocumentationProvider.GetId(propertyInfo); var declaringAssembly = propertyInfo.DeclaringType.Assembly; var documentationDescriptor = CreateDocumentationDescriptor(declaringAssembly, id); - if (documentationDescriptor != null) { return new TagHelperAttributeDesignTimeDescriptor @@ -90,31 +93,51 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers return null; } - private static DocumentationDescriptor CreateDocumentationDescriptor(Assembly assembly, string id) + private XmlDocumentationProvider GetXmlDocumentationProvider(Assembly assembly) { - var assemblyLocation = assembly.Location; + var hashCodeCombiner = HashCodeCombiner.Start(); + hashCodeCombiner.Add(assembly); + hashCodeCombiner.Add(CultureInfo.CurrentCulture); + var cacheKey = hashCodeCombiner.CombinedHash; - if (string.IsNullOrEmpty(assemblyLocation) && !string.IsNullOrEmpty(assembly.CodeBase)) + var documentationProvider = _documentationProviderCache.GetOrAdd(cacheKey, valueFactory: _ => { - var uri = new UriBuilder(assembly.CodeBase); + var assemblyLocation = assembly.Location; - // Normalize the path to a UNC path. This will remove things like file:// from start of the uri.Path. - assemblyLocation = Uri.UnescapeDataString(uri.Path); - } + if (string.IsNullOrEmpty(assemblyLocation) && !string.IsNullOrEmpty(assembly.CodeBase)) + { + var uri = new UriBuilder(assembly.CodeBase); + + // Normalize the path to UNC path. This will remove things like file:// from start of uri.Path. + assemblyLocation = Uri.UnescapeDataString(uri.Path); + } + + // Couldn't resolve a valid assemblyLocation. + if (string.IsNullOrEmpty(assemblyLocation)) + { + return null; + } + + var xmlDocumentationFile = GetXmlDocumentationFile(assembly, assemblyLocation); + + // Only want to process the file if it exists. + if (xmlDocumentationFile != null) + { + return new XmlDocumentationProvider(xmlDocumentationFile.FullName); + } - // Couldn't resolve a valid assemblyLocation. - if (string.IsNullOrEmpty(assemblyLocation)) - { return null; - } + }); - var xmlDocumentationFile = GetXmlDocumentationFile(assembly, assemblyLocation); + return documentationProvider; + } - // Only want to process the file if it exists. - if (xmlDocumentationFile != null) + private DocumentationDescriptor CreateDocumentationDescriptor(Assembly assembly, string id) + { + var documentationProvider = GetXmlDocumentationProvider(assembly); + + if (documentationProvider != null) { - var documentationProvider = new XmlDocumentationProvider(xmlDocumentationFile.FullName); - var summary = documentationProvider.GetSummary(id); var remarks = documentationProvider.GetRemarks(id); diff --git a/src/Microsoft.AspNet.Razor.Runtime/project.json b/src/Microsoft.AspNet.Razor.Runtime/project.json index 6c6f552f35..1c8f2f4d7e 100644 --- a/src/Microsoft.AspNet.Razor.Runtime/project.json +++ b/src/Microsoft.AspNet.Razor.Runtime/project.json @@ -26,6 +26,12 @@ "frameworkAssemblies": { "System.Xml": "4.0.0.0", "System.Xml.Linq": "4.0.0.0" + }, + "dependencies": { + "Microsoft.Extensions.HashCodeCombiner.Sources": { + "type": "build", + "version": "1.0.0-*" + } } }, "dotnet5.4": { diff --git a/test/Microsoft.AspNet.Razor.Runtime.Precompilation.Test/PrecompilationTagHelperDescriptorFactoryTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Precompilation.Test/PrecompilationTagHelperDescriptorFactoryTest.cs index 9fad425be0..b1da983372 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Precompilation.Test/PrecompilationTagHelperDescriptorFactoryTest.cs +++ b/test/Microsoft.AspNet.Razor.Runtime.Precompilation.Test/PrecompilationTagHelperDescriptorFactoryTest.cs @@ -37,12 +37,12 @@ namespace Microsoft.AspNet.Razor.Runtime.Precompilation { // Arrange var errorSink = new ErrorSink(); + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(tagHelperType), - designTime: false, errorSink: errorSink); // Assert diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/Runtime/TagHelpers/RuntimeTagHelperDescriptorFactoryTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/Runtime/TagHelpers/RuntimeTagHelperDescriptorFactoryTest.cs index 78d88a4842..d25c28939f 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/Runtime/TagHelpers/RuntimeTagHelperDescriptorFactoryTest.cs +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/Runtime/TagHelpers/RuntimeTagHelperDescriptorFactoryTest.cs @@ -25,12 +25,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var objectAssemblyName = typeof(object).GetTypeInfo().Assembly.GetName().Name; var expectedDescriptor = CreateTagHelperDescriptor("object", "System.Object", objectAssemblyName); + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( objectAssemblyName, GetTypeInfo(typeof(object)), - designTime: false, errorSink: errorSink); // Assert @@ -48,12 +48,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange var errorSink = new ErrorSink(); + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(tagHelperType), - designTime: false, errorSink: errorSink); // Assert @@ -137,12 +137,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange var errorSink = new ErrorSink(); + var factory = new TagHelperDescriptorFactory(designTime: true); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(tagHelperType), - designTime: true, errorSink: errorSink); // Assert diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/Runtime/TagHelpers/TagHelperDescriptorFactoryTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/Runtime/TagHelpers/TagHelperDescriptorFactoryTest.cs index b2df198292..4a396613b3 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/Runtime/TagHelpers/TagHelperDescriptorFactoryTest.cs +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/Runtime/TagHelpers/TagHelperDescriptorFactoryTest.cs @@ -88,12 +88,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange var errorSink = new ErrorSink(); + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(tagHelperType), - designTime: false, errorSink: errorSink); // Assert @@ -177,12 +177,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange var errorSink = new ErrorSink(); + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(tagHelperType), - designTime: false, errorSink: errorSink); // Assert @@ -262,12 +262,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange var errorSink = new ErrorSink(); + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(tagHelperType), - designTime: false, errorSink: errorSink); // Assert @@ -351,12 +351,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange var errorSink = new ErrorSink(); + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(tagHelperType), - designTime: false, errorSink: errorSink); // Assert @@ -587,12 +587,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange var errorSink = new ErrorSink(); + var factory = new TagHelperDescriptorFactory(designTime); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(tagHelperType), - designTime, errorSink); // Assert @@ -789,12 +789,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange var errorSink = new ErrorSink(); + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(tagHelperType), - designTime: false, errorSink: errorSink); // Assert @@ -838,12 +838,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange var errorSink = new ErrorSink(); + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(tagHelperType), - designTime: false, errorSink: errorSink); // Assert @@ -875,12 +875,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers CreateTagHelperAttributeDescriptor("Something-Else", validProperty2) }) }; + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(typeof(OverriddenAttributeTagHelper)), - designTime: false, errorSink: errorSink); // Assert @@ -909,12 +909,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers CreateTagHelperAttributeDescriptor("Something-Else", validProperty2) }) }; + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(typeof(InheritedOverriddenAttributeTagHelper)), - designTime: false, errorSink: errorSink); // Assert @@ -943,12 +943,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers CreateTagHelperAttributeDescriptor("Something-Else", validProperty2) }) }; + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(typeof(InheritedNotOverriddenAttributeTagHelper)), - designTime: false, errorSink: errorSink); // Assert Assert.Empty(errorSink.Errors); @@ -973,12 +973,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers TypeName = typeof(int).FullName } }); + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(typeof(InheritedSingleAttributeTagHelper)), - designTime: false, errorSink: errorSink); // Assert @@ -1001,12 +1001,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { CreateTagHelperAttributeDescriptor("int-attribute", intProperty) }); + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(typeof(SingleAttributeTagHelper)), - designTime: false, errorSink: new ErrorSink()); // Assert @@ -1030,12 +1030,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { CreateTagHelperAttributeDescriptor("valid-attribute", validProperty) }); + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(typeof(MissingAccessorTagHelper)), - designTime: false, errorSink: errorSink); // Assert @@ -1059,12 +1059,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { CreateTagHelperAttributeDescriptor("valid-attribute", validProperty) }); + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(typeof(NonPublicAccessorTagHelper)), - designTime: false, errorSink: errorSink); // Assert @@ -1091,12 +1091,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers TypeName = typeof(object).FullName } }); + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(typeof(NotBoundAttributeTagHelper)), - designTime: false, errorSink: errorSink); // Assert @@ -1110,12 +1110,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange var errorSink = new ErrorSink(); + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(typeof(DuplicateAttributeNameTagHelper)), - designTime: false, errorSink: errorSink); // Assert @@ -1159,12 +1159,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers } }) }; + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(typeof(MultiTagTagHelper)), - designTime: false, errorSink: errorSink); // Assert @@ -1191,12 +1191,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { CreateTagHelperAttributeDescriptor("valid-attribute", validProp) }); + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(typeof(InheritedMultiTagTagHelper)), - designTime: false, errorSink: errorSink); // Assert @@ -1221,12 +1221,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers typeof(DuplicateTagNameTagHelper).FullName, AssemblyName) }; + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(typeof(DuplicateTagNameTagHelper)), - designTime: false, errorSink: errorSink); // Assert @@ -1251,12 +1251,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers typeof(OverrideNameTagHelper).FullName, AssemblyName), }; + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(typeof(OverrideNameTagHelper)), - designTime: false, errorSink: errorSink); // Assert @@ -1439,12 +1439,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange var errorSink = new ErrorSink(); + var factory = new TagHelperDescriptorFactory(designTime: false); // Act - var descriptors = TagHelperDescriptorFactory.CreateDescriptors( + var descriptors = factory.CreateDescriptors( AssemblyName, GetTypeInfo(type), - designTime: false, errorSink: errorSink); // Assert diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/Runtime/TagHelpers/TagHelperDescriptorResolverTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/Runtime/TagHelpers/TagHelperDescriptorResolverTest.cs index 3dcfcfc69f..ca6241f0f0 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/Runtime/TagHelpers/TagHelperDescriptorResolverTest.cs +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/Runtime/TagHelpers/TagHelperDescriptorResolverTest.cs @@ -1381,7 +1381,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers private class TestTagHelperDescriptorResolver : TagHelperDescriptorResolver { public TestTagHelperDescriptorResolver(TagHelperTypeResolver typeResolver) - : base(typeResolver, designTime: false) + : base(typeResolver, new TagHelperDescriptorFactory(designTime: false)) { } diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/Runtime/TagHelpers/TagHelperDesignTimeDescriptorFactoryTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/Runtime/TagHelpers/TagHelperDesignTimeDescriptorFactoryTest.cs index 31d581c75c..e454f92223 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/Runtime/TagHelpers/TagHelperDesignTimeDescriptorFactoryTest.cs +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/Runtime/TagHelpers/TagHelperDesignTimeDescriptorFactoryTest.cs @@ -74,8 +74,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers Type tagHelperType, TagHelperDesignTimeDescriptor expectedDescriptor) { + // Arrange + var factory = new TagHelperDesignTimeDescriptorFactory(); + // Act - var descriptors = TagHelperDesignTimeDescriptorFactory.CreateDescriptor(tagHelperType); + var descriptors = factory.CreateDescriptor(tagHelperType); // Assert Assert.Equal(expectedDescriptor, descriptors, TagHelperDesignTimeDescriptorComparer.Default); @@ -142,8 +145,11 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers Type tagHelperType, TagHelperDesignTimeDescriptor expectedDesignTimeDescriptor) { + // Arrange + var factory = new TagHelperDesignTimeDescriptorFactory(); + // Act - var designTimeDescriptor = TagHelperDesignTimeDescriptorFactory.CreateDescriptor(tagHelperType); + var designTimeDescriptor = factory.CreateDescriptor(tagHelperType); // Assert Assert.Equal(expectedDesignTimeDescriptor, designTimeDescriptor, TagHelperDesignTimeDescriptorComparer.Default); @@ -219,17 +225,59 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange TagHelperDesignTimeDescriptor designTimeDescriptor; + var factory = new TagHelperDesignTimeDescriptorFactory(); // Act using (new CultureReplacer(culture)) { - designTimeDescriptor = TagHelperDesignTimeDescriptorFactory.CreateDescriptor(tagHelperType); + designTimeDescriptor = factory.CreateDescriptor(tagHelperType); } // Assert Assert.Equal(expectedDesignTimeDescriptor, designTimeDescriptor, TagHelperDesignTimeDescriptorComparer.Default); } + [Fact] + public void CreateDescriptor_WithLocalizedType_CachesBasedOnCulture() + { + // Arrange + var factory = new TagHelperDesignTimeDescriptorFactory(); + var expectedFRDesignTimeDescriptor = new TagHelperDesignTimeDescriptor + { + Summary = "fr-FR: " + TypeSummary, + Remarks = "fr-FR: " + TypeRemarks, + OutputElementHint = "p", + }; + var expectedNLBEDesignTimeDescriptor = new TagHelperDesignTimeDescriptor + { + Summary = "nl-BE: " + TypeSummary, + Remarks = "nl-BE: " + TypeRemarks, + OutputElementHint = "p", + }; + var tagHelperType = CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null); + TagHelperDesignTimeDescriptor frDesignTimeDescriptor, nlBEDesignTimeDescriptor; + + // Act + using (new CultureReplacer("fr-FR")) + { + frDesignTimeDescriptor = factory.CreateDescriptor(tagHelperType); + } + using (new CultureReplacer("nl-BE")) + { + nlBEDesignTimeDescriptor = factory.CreateDescriptor(tagHelperType); + } + + // Assert + Assert.Equal( + expectedFRDesignTimeDescriptor, + frDesignTimeDescriptor, + TagHelperDesignTimeDescriptorComparer.Default); + Assert.Equal( + expectedNLBEDesignTimeDescriptor, + nlBEDesignTimeDescriptor, + TagHelperDesignTimeDescriptorComparer.Default); + } + public static TheoryData CreateAttributeDescriptor_PropertyDocumentationData { get @@ -374,9 +422,10 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var mockPropertyInfo = new Mock(); mockPropertyInfo.Setup(propertyInfo => propertyInfo.DeclaringType).Returns(tagHelperType); mockPropertyInfo.Setup(propertyInfo => propertyInfo.Name).Returns(propertyName); + var factory = new TagHelperDesignTimeDescriptorFactory(); // Act - var designTimeDescriptor = TagHelperDesignTimeDescriptorFactory.CreateAttributeDescriptor( + var designTimeDescriptor = factory.CreateAttributeDescriptor( mockPropertyInfo.Object); // Assert @@ -456,11 +505,12 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers .Setup(propertyInfo => propertyInfo.Name) .Returns(nameof(DocumentedTagHelper.RemarksAndSummaryProperty)); TagHelperAttributeDesignTimeDescriptor designTimeDescriptor; + var factory = new TagHelperDesignTimeDescriptorFactory(); // Act using (new CultureReplacer(culture)) { - designTimeDescriptor = TagHelperDesignTimeDescriptorFactory.CreateAttributeDescriptor( + designTimeDescriptor = factory.CreateAttributeDescriptor( mockPropertyInfo.Object); } @@ -471,6 +521,50 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers TagHelperAttributeDesignTimeDescriptorComparer.Default); } + [Fact] + public void CreateDescriptor_WithLocalizedProperty_CachesBasedOnCulture() + { + // Arrange + var tagHelperType = CreateDocumentationTagHelperType(LocalizedDocumentedAssemblyLocation, codeBase: null); + var mockPropertyInfo = new Mock(); + mockPropertyInfo.Setup(propertyInfo => propertyInfo.DeclaringType).Returns(tagHelperType); + mockPropertyInfo + .Setup(propertyInfo => propertyInfo.Name) + .Returns(nameof(DocumentedTagHelper.RemarksAndSummaryProperty)); + var factory = new TagHelperDesignTimeDescriptorFactory(); + var expectedFRDesignTimeDescriptor = new TagHelperAttributeDesignTimeDescriptor + { + Summary = "fr-FR: " + PropertyWithSummaryAndRemarks_Summary, + Remarks = "fr-FR: " + PropertyWithSummaryAndRemarks_Remarks + }; + var expectedNLBEDesignTimeDescriptor = new TagHelperAttributeDesignTimeDescriptor + { + Summary = "nl-BE: " + PropertyWithSummaryAndRemarks_Summary, + Remarks = "nl-BE: " + PropertyWithSummaryAndRemarks_Remarks + }; + TagHelperAttributeDesignTimeDescriptor frDesignTimeDescriptor, nlBEDesignTimeDescriptor; + + // Act + using (new CultureReplacer("fr-FR")) + { + frDesignTimeDescriptor = factory.CreateAttributeDescriptor(mockPropertyInfo.Object); + } + using (new CultureReplacer("nl-BE")) + { + nlBEDesignTimeDescriptor = factory.CreateAttributeDescriptor(mockPropertyInfo.Object); + } + + // Assert + Assert.Equal( + expectedFRDesignTimeDescriptor, + frDesignTimeDescriptor, + TagHelperAttributeDesignTimeDescriptorComparer.Default); + Assert.Equal( + expectedNLBEDesignTimeDescriptor, + nlBEDesignTimeDescriptor, + TagHelperAttributeDesignTimeDescriptorComparer.Default); + } + private static Type CreateDocumentationTagHelperType(string location, string codeBase) { return CreateType(location, codeBase); diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/project.json b/test/Microsoft.AspNet.Razor.Runtime.Test/project.json index 18f5b77b49..485a4d1d9d 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/project.json +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/project.json @@ -11,10 +11,6 @@ "type": "build" }, "Microsoft.AspNet.Testing": "1.0.0-*", - "Microsoft.Extensions.HashCodeCombiner.Sources": { - "type": "build", - "version": "1.0.0-*" - }, "Microsoft.Extensions.WebEncoders": "1.0.0-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" }, @@ -27,6 +23,13 @@ "Moq": "4.2.1312.1622" } }, - "dnxcore50": {} + "dnxcore50": { + "dependencies": { + "Microsoft.Extensions.HashCodeCombiner.Sources": { + "type": "build", + "version": "1.0.0-*" + } + } + } } }